* [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module
@ 2011-10-28 19:54 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked Pavel Shilovsky
` (23 more replies)
0 siblings, 24 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
This patchset enables SMB2 support with CONFIG_CIFS_SMB2 Kconfig option. While many operations work now, there are a lot of places to do here (brlocks, acls, prefixpaths, set_attr, etc).
You can test it by building with CONFIG_CIFS_SMB2 enabled and mounting with vers=2 option.
The second version includes fixes of sparse and compile warnings and cleanups of the oplock/readdir code (that Steve reported about).
Pavel Shilovsky (37):
CIFS: Add SMB2 transport routines
CIFS: Expand cifs mid structure to keep SMB2 related fields
CIFS: Make demultiplex_thread work with SMB2 code
CIFS: Get mount/umount work with SMB2 protocol
CIFS: Simplify SMB2 query info
CIFS: Add SMB2 inode/dentry ops structures
CIFS: Add SMB2 support for mkdir operation
CIFS: Add SMB2 support for rmdir operation
CIFS: Add SMB2 support for unlink operation
CIFS: Add SMB2 support for open/close file operations
CIFS: Add SMB2 support for reopen file operation
CIFS: Add SMB2 support for cifs_iovec_write
CIFS: Add SMB2 support for cifs_iovec_read
CIFS: Add address space ops structures for SMB2
CIFS: Add read related address space operations for SMB2
CIFS: Add write related address space operations for SMB2
CIFS: Respect max buf size for SMB2 read and write
CIFS: Temporarily disable set inode info for SMB2
CIFS: Add writepages support for SMB2
CIFS: Add readpages support for SMB2
CIFS: Add echo request support for SMB2
CIFS: Add SMB2 support for create operation
CIFS: Add readdir support for SMB2
CIFS: Add SMB2 support for rename operation
CIFS: Add SMB2 support for hardlink operation
CIFS: Add SMB2 support for flush operation
CIFS: Add NTLMSSP sec type to defaults
CIFS: Disable SMB2.1 protocol negotiating
CIFS: Process oplocks for SMB2
CIFS: Process STATUS_PENDING responses for SMB2
CIFS: Request SMB2.1 leases
CIFS: Process oplock/lease break for SMB2/2.1
CIFS: Add strictcache i/o for SMB2
CIFS: Process signing for SMB2_logoff
CIFS: Change Makefile to support CONFIG_CIFS_SMB2
CIFS: Add statfs support for SMB2
CIFS: Disable lock call for SMB2 since we don't support it
Shirish Pargaonkar (1):
CIFS: Enable signing in SMB2
Steve French (15):
CIFS: Update cifs global structures to handle smb2 sessions
CIFS: Allow SMB2 statistics to be tracked
CIFS: Check for smb2 vs. cifs in find_tcp_session
CIFS: Do not try to dump cifs mids from smb2 sessions
CIFS: wait_for_free_request needs to wait on credits returned by
server (for SMB2)
CIFS: Add missing unicode handling routines needed by smb2
CIFS: Add structure definitions for SMB2 PDUs
CIFS: Add initial SMB2 worker functions
CIFS: Allocating SMB2 mids (multiplex identifier structures)
CIFS: Add routines to free SMB2 mids
CIFS: Add sync_smb2_mid_result
CIFS: Add error mapping function for smb2 status codes to posix
errors
[CIFS] Add SMB2 support for cifs_get_file_info
CIFS: Introduce SMB2 Kconfig option
CIFS: Introduce smb2 mounts as vers=2
fs/cifs/Kconfig | 21 +
fs/cifs/Makefile | 4 +
fs/cifs/TODO | 2 +
fs/cifs/cifs_debug.c | 346 ++++---
fs/cifs/cifs_debug.h | 12 +-
fs/cifs/cifs_fs_sb.h | 4 +-
fs/cifs/cifs_unicode.c | 61 +
fs/cifs/cifs_unicode.h | 7 +
fs/cifs/cifsacl.h | 2 +-
fs/cifs/cifsencrypt.c | 30 +-
fs/cifs/cifsfs.c | 173 ++--
fs/cifs/cifsfs.h | 6 +-
fs/cifs/cifsglob.h | 193 +++-
fs/cifs/cifsproto.h | 114 ++-
fs/cifs/cifssmb.c | 157 ++-
fs/cifs/connect.c | 382 ++++++--
fs/cifs/dir.c | 6 +-
fs/cifs/file.c | 655 ++++++++---
fs/cifs/inode.c | 153 ++-
fs/cifs/maperror.c | 1830 ++++++++++++++++++++++++++++++
fs/cifs/misc.c | 21 +-
fs/cifs/nterr.h | 1 +
fs/cifs/ntlmssp.h | 10 +
fs/cifs/readdir.c | 4 +-
fs/cifs/sess.c | 8 +-
fs/cifs/smb2dir.c | 79 ++
fs/cifs/smb2file.c | 560 +++++++++
fs/cifs/smb2glob.h | 215 ++++
fs/cifs/smb2inode.c | 829 ++++++++++++++
fs/cifs/smb2link.c | 108 ++
fs/cifs/smb2misc.c | 523 +++++++++
fs/cifs/smb2pdu.c | 2887 +++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 1064 +++++++++++++++++
fs/cifs/smb2proto.h | 280 +++++
fs/cifs/smb2readdir.c | 593 ++++++++++
fs/cifs/smb2sess.c | 109 ++
fs/cifs/smb2status.h | 1782 +++++++++++++++++++++++++++++
fs/cifs/smb2transport.c | 678 +++++++++++
fs/cifs/transport.c | 193 ++--
39 files changed, 13321 insertions(+), 781 deletions(-)
create mode 100644 fs/cifs/maperror.c
create mode 100644 fs/cifs/smb2dir.c
create mode 100644 fs/cifs/smb2file.c
create mode 100644 fs/cifs/smb2glob.h
create mode 100644 fs/cifs/smb2inode.c
create mode 100644 fs/cifs/smb2link.c
create mode 100644 fs/cifs/smb2misc.c
create mode 100644 fs/cifs/smb2pdu.c
create mode 100644 fs/cifs/smb2pdu.h
create mode 100644 fs/cifs/smb2proto.h
create mode 100644 fs/cifs/smb2readdir.c
create mode 100644 fs/cifs/smb2sess.c
create mode 100644 fs/cifs/smb2status.h
create mode 100644 fs/cifs/smb2transport.c
^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH v2 01/53] CIFS: Update cifs global structures to handle smb2 sessions
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 04/53] CIFS: Do not try to dump cifs mids from " Pavel Shilovsky
` (26 subsequent siblings)
27 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
cifsglob.h defines the per socket structures
smb2 could already use the per-smb socket structures,
but to use the per-socket structures required additional
optional fields. (Note that the tree connection
structure differs substantially and will probably endup
as a based tcon structure used by smb2 and cifs and a
union for the stats.
Also save whole smb2 dialect minor version - Jeff suggested
that easier to handle future version updates if we treat
the minor version in its native wire form rather than as
series of booleans.
Prepratory to merging more of the smb2 global routines
1) cleanup some unused structs and defines
2) add in externs for smb2 debugging routines
smb2 needs to save off device_type on tcon and share_flags on tcon and
session flags and subdialect on sessionsetup
Acked-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/TODO | 2 ++
fs/cifs/cifs_debug.h | 12 +++++++++---
fs/cifs/cifs_fs_sb.h | 4 +++-
fs/cifs/cifsacl.h | 2 +-
fs/cifs/cifsglob.h | 44 +++++++++++++++++++++++++++++++++-----------
fs/cifs/cifspdu.h | 2 ++
fs/cifs/cifssmb.c | 2 +-
fs/cifs/sess.c | 2 +-
8 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 355abcd..2c68abc 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,5 +1,7 @@
Version 1.53 May 20, 2008
+PUT IN WARNING FOR NTLMV2 becoming default
+
A Partial List of Missing Features
==================================
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index 8942b28..fec0743 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) International Business Machines Corp., 2000,2002
+ * Copyright (c) International Business Machines Corp., 2000,2011
* Modified by Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
*
* This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define CIFS_DEBUG /* BB temporary */
+#define CIFS_DEBUG /* remove to disable cifserror logging */
#ifndef _H_CIFS_DEBUG
#define _H_CIFS_DEBUG
@@ -28,6 +28,9 @@ void cifs_dump_mem(char *label, void *data, int length);
#define DBG2 2
void cifs_dump_detail(struct smb_hdr *);
void cifs_dump_mids(struct TCP_Server_Info *);
+#ifdef CONFIG_CIFS_SMB2
+void smb2_dump_detail(struct smb2_hdr *);
+#endif /* CONFIG_CIFS_SMB2 */
#else
#define DBG2 0
#endif
@@ -37,12 +40,15 @@ void dump_smb(struct smb_hdr *, int);
#define CIFS_RC 0x02
#define CIFS_TIMER 0x04
+#ifdef CONFIG_CIFS_SMB2
+void dump_smb2(struct smb2_hdr *, int);
+#endif /* CONFIG_CIFS_SMB2 */
+
/*
* debug ON
* --------
*/
#ifdef CIFS_DEBUG
-
/* information message: e.g., configuration, major event */
extern int cifsFYI;
#define cifsfyi(fmt, arg...) \
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 500d658..8e6dd9a 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifs_fs_sb.h
*
- * Copyright (c) International Business Machines Corp., 2002,2004
+ * Copyright (c) International Business Machines Corp., 2002,2010
* Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
*
* This library is free software; you can redistribute it and/or modify
@@ -24,10 +24,12 @@
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
#define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
+/* SERVER_INUM is always set for SMB2 */
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+/* The following two are not supported for SMB2 */
#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible*/
#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index 5c902c7..ba9a9db 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsacl.h
*
- * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) International Business Machines Corp., 2007,2010
* Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
*
* This library is free software; you can redistribute it and/or modify
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8238aa1..4c38b04 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsglob.h
*
- * Copyright (C) International Business Machines Corp., 2002,2008
+ * Copyright (C) International Business Machines Corp., 2002,2011
* Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
* Jeremy Allison (jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org)
*
@@ -259,7 +259,7 @@ struct TCP_Server_Info {
struct mutex srv_mutex;
struct task_struct *tsk;
char server_GUID[16];
- char sec_mode;
+ __u16 sec_mode;
bool session_estab; /* mark when very first sess is established */
u16 dialect; /* dialect index that server chose */
enum securityEnum secType;
@@ -305,6 +305,18 @@ struct TCP_Server_Info {
atomic_t in_send; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#endif
+#ifdef CONFIG_CIFS_SMB2
+ wait_queue_head_t read_q; /* used by readpages */
+ atomic_t active_readpage_req; /* used by readpages */
+ atomic_t resp_rdy; /* used by readpages and demultiplex */
+ __le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
+ struct task_struct *observe;
+ char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
+ __u64 current_smb2_mid; /* multiplex id - rotating counter */
+ __u8 speed; /* helps us identify if this is a slow link */
+ unsigned int max_read;
+ unsigned int max_write;
+#endif /* CONFIG_CIFS_SMB2 */
};
/*
@@ -354,7 +366,7 @@ struct cifs_ses {
char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */
- int Suid; /* remote smb uid */
+ __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;
@@ -367,6 +379,9 @@ struct cifs_ses {
struct session_key auth_key;
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
bool need_reconnect:1; /* connection reset, uid now invalid */
+#ifdef CONFIG_CIFS_SMB2
+ __u16 session_flags;
+#endif /* CONFIG_CIFS_SMB2 */
};
/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
@@ -376,6 +391,7 @@ 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
+#define CIFS_SES_SMB2 16
/*
* there is one of these for each connection to a resource on a particular
* session
@@ -388,7 +404,7 @@ struct cifs_tcon {
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
char *nativeFileSystem;
char *password; /* for share-level security */
- __u16 tid; /* The 2 byte tree id */
+ __u32 tid; /* The 4 byte tree id */
__u16 Flags; /* optional support bits */
enum statusEnum tidStatus;
#ifdef CONFIG_CIFS_STATS
@@ -436,6 +452,7 @@ struct cifs_tcon {
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
+ bool print:1; /* set if connection to printer share */
bool retry:1;
bool nocase:1;
bool seal:1; /* transport encryption for this mounted share */
@@ -444,6 +461,15 @@ struct cifs_tcon {
bool local_lease:1; /* check leases (only) on local system not remote */
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool need_reconnect:1; /* connection reset, tid now invalid */
+ bool bad_network_name:1;
+#ifdef CONFIG_CIFS_SMB2
+ __u32 capabilities;
+ __u32 share_flags;
+ __u32 maximal_access;
+ __u32 vol_serial_number;
+ __le64 vol_create_time;
+ struct mutex tcon_mutex;
+#endif /* CONFIG_CIFS_SMB2 */
#ifdef CONFIG_CIFS_FSCACHE
u64 resource_id; /* server resource id */
struct fscache_cookie *fscache; /* cookie for share */
@@ -802,6 +828,7 @@ struct cifs_fattr {
struct timespec cf_atime;
struct timespec cf_mtime;
struct timespec cf_ctime;
+ u32 ea_size;
};
static inline void free_dfs_info_param(struct dfs_info3_param *param)
@@ -833,6 +860,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define MID_RETRY_NEEDED 8 /* session closed while this request out */
#define MID_RESPONSE_MALFORMED 0x10
#define MID_SHUTDOWN 0x20
+#define MID_NO_RESPONSE_NEEDED 0x40
/* Types of response buffer returned from SendReceive2 */
#define CIFS_NO_BUFFER 0 /* Response buffer not returned */
@@ -841,6 +869,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define CIFS_IOVEC 4 /* array of response buffers */
/* Type of Request to SendReceive2 */
+#define CIFS_STD_OP 0
#define CIFS_BLOCKING_OP 1 /* operation can block */
#define CIFS_ASYNC_OP 2 /* do not wait for response */
#define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */
@@ -891,13 +920,6 @@ require use of the stronger protocol */
#define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
-/*
- *****************************************************************
- * All constants go here
- *****************************************************************
- */
-
-#define UID_HASH (16)
/*
* Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 3fb03e2..d1cfc81 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -428,6 +428,8 @@ struct smb_hdr {
__u8 WordCount;
} __attribute__((packed));
+struct smb2_hdr;
+
/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
static inline void *
BCC(struct smb_hdr *smb)
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 6600aa2..ea7b813 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -457,7 +457,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
- server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
+ server->sec_mode = le16_to_cpu(rsp->SecurityMode);
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index c7d80e2..5b7c94f 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -895,7 +895,7 @@ ssetup_ntlmssp_authenticate:
if (action & GUEST_LOGIN)
cFYI(1, "Guest login"); /* BB mark SesInfo struct? */
ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
- cFYI(1, "UID = %d ", ses->Suid);
+ cFYI(1, "UID = %llu ", ses->Suid);
/* response can have either 3 or 4 word count - Samba sends 3 */
/* and lanman response is 3 */
bytes_remaining = get_bcc(smb_buf);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-29 4:48 ` Jeff Layton
2011-10-28 19:54 ` [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session Pavel Shilovsky
` (22 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Steve French
From: Steve French <sfrench@us.ibm.com>
Adding SMB2 statistics requires changes to the way cifs handles stats.
Since there are only 19 command codes, it also is easier to track by exact
command code than it was for cifs. Turn the counters for protocol
ops sent to be a union (one struct for cifs, one for smb2). While at it
split out the functions which clear stats and prints stats into their own
subfunctions so they are easy to read and don't go past 80 columns.
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifs_debug.c | 146 ++++++++++++++++++++++++++++++-------------------
fs/cifs/cifsglob.h | 56 ++++++++++++-------
fs/cifs/cifssmb.c | 54 +++++++++---------
fs/cifs/misc.c | 2 +-
4 files changed, 152 insertions(+), 106 deletions(-)
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 84e8c07..8ccdb15 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -249,6 +249,55 @@ static const struct file_operations cifs_debug_data_proc_fops = {
};
#ifdef CONFIG_CIFS_STATS
+
+#ifdef CONFIG_CIFS_SMB2
+static void smb2_clear_stats(struct cifs_tcon *tcon)
+{
+ int i;
+
+ atomic_set(&tcon->num_smbs_sent, 0);
+ for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
+ atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
+ atomic_set(&tcon->stats.smb2_stats.smb2_com_fail[i], 0);
+ }
+}
+#endif /* CONFIG_CIFS_SMB2 */
+
+static void clear_cifs_stats(struct cifs_tcon *tcon)
+{
+ atomic_set(&tcon->num_smbs_sent, 0);
+
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2) {
+ smb2_clear_stats(tcon);
+ return;
+ }
+#endif /* CONFIG_CIFS_SMB2 */
+
+ /* cifs specific statistics, not applicable to smb2 sessions */
+ atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
+ atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
+}
+
static ssize_t cifs_stats_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos)
{
@@ -279,25 +328,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
tcon = list_entry(tmp3,
struct cifs_tcon,
tcon_list);
- atomic_set(&tcon->num_smbs_sent, 0);
- atomic_set(&tcon->num_writes, 0);
- atomic_set(&tcon->num_reads, 0);
- atomic_set(&tcon->num_oplock_brks, 0);
- atomic_set(&tcon->num_opens, 0);
- atomic_set(&tcon->num_posixopens, 0);
- atomic_set(&tcon->num_posixmkdirs, 0);
- atomic_set(&tcon->num_closes, 0);
- atomic_set(&tcon->num_deletes, 0);
- atomic_set(&tcon->num_mkdirs, 0);
- atomic_set(&tcon->num_rmdirs, 0);
- atomic_set(&tcon->num_renames, 0);
- atomic_set(&tcon->num_t2renames, 0);
- atomic_set(&tcon->num_ffirst, 0);
- atomic_set(&tcon->num_fnext, 0);
- atomic_set(&tcon->num_fclose, 0);
- atomic_set(&tcon->num_hardlinks, 0);
- atomic_set(&tcon->num_symlinks, 0);
- atomic_set(&tcon->num_locks, 0);
+ clear_cifs_stats(tcon);
}
}
}
@@ -307,6 +338,44 @@ static ssize_t cifs_stats_proc_write(struct file *file,
return count;
}
+static void cifs_stats_print(struct seq_file *m, struct cifs_tcon *tcon)
+{
+ if (tcon->need_reconnect)
+ seq_puts(m, "\tDISCONNECTED ");
+ seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
+ atomic_read(&tcon->num_smbs_sent),
+ atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
+ seq_printf(m, "\nReads: %d Bytes: %lld",
+ atomic_read(&tcon->stats.cifs_stats.num_reads),
+ (long long)(tcon->bytes_read));
+ seq_printf(m, "\nWrites: %d Bytes: %lld",
+ atomic_read(&tcon->stats.cifs_stats.num_writes),
+ (long long)(tcon->bytes_written));
+ seq_printf(m, "\nFlushes: %d",
+ atomic_read(&tcon->stats.cifs_stats.num_flushes));
+ seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
+ atomic_read(&tcon->stats.cifs_stats.num_locks),
+ atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
+ atomic_read(&tcon->stats.cifs_stats.num_symlinks));
+ seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
+ atomic_read(&tcon->stats.cifs_stats.num_opens),
+ atomic_read(&tcon->stats.cifs_stats.num_closes),
+ atomic_read(&tcon->stats.cifs_stats.num_deletes));
+ seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
+ atomic_read(&tcon->stats.cifs_stats.num_posixopens),
+ atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
+ seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
+ atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
+ atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
+ seq_printf(m, "\nRenames: %d T2 Renames %d",
+ atomic_read(&tcon->stats.cifs_stats.num_renames),
+ atomic_read(&tcon->stats.cifs_stats.num_t2renames));
+ seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
+ atomic_read(&tcon->stats.cifs_stats.num_ffirst),
+ atomic_read(&tcon->stats.cifs_stats.num_fnext),
+ atomic_read(&tcon->stats.cifs_stats.num_fclose));
+}
+
static int cifs_stats_proc_show(struct seq_file *m, void *v)
{
int i;
@@ -354,44 +423,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
tcon_list);
i++;
seq_printf(m, "\n%d) %s", i, tcon->treeName);
- if (tcon->need_reconnect)
- seq_puts(m, "\tDISCONNECTED ");
- seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
- atomic_read(&tcon->num_smbs_sent),
- atomic_read(&tcon->num_oplock_brks));
- seq_printf(m, "\nReads: %d Bytes: %lld",
- atomic_read(&tcon->num_reads),
- (long long)(tcon->bytes_read));
- seq_printf(m, "\nWrites: %d Bytes: %lld",
- atomic_read(&tcon->num_writes),
- (long long)(tcon->bytes_written));
- seq_printf(m, "\nFlushes: %d",
- atomic_read(&tcon->num_flushes));
- seq_printf(m, "\nLocks: %d HardLinks: %d "
- "Symlinks: %d",
- atomic_read(&tcon->num_locks),
- atomic_read(&tcon->num_hardlinks),
- atomic_read(&tcon->num_symlinks));
- seq_printf(m, "\nOpens: %d Closes: %d "
- "Deletes: %d",
- atomic_read(&tcon->num_opens),
- atomic_read(&tcon->num_closes),
- atomic_read(&tcon->num_deletes));
- seq_printf(m, "\nPosix Opens: %d "
- "Posix Mkdirs: %d",
- atomic_read(&tcon->num_posixopens),
- atomic_read(&tcon->num_posixmkdirs));
- seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
- atomic_read(&tcon->num_mkdirs),
- atomic_read(&tcon->num_rmdirs));
- seq_printf(m, "\nRenames: %d T2 Renames %d",
- atomic_read(&tcon->num_renames),
- atomic_read(&tcon->num_t2renames));
- seq_printf(m, "\nFindFirst: %d FNext %d "
- "FClose %d",
- atomic_read(&tcon->num_ffirst),
- atomic_read(&tcon->num_fnext),
- atomic_read(&tcon->num_fclose));
+ cifs_stats_print(m, tcon);
}
}
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4c38b04..6dfc7ef 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -292,6 +292,7 @@ struct TCP_Server_Info {
bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */
bool large_buf; /* is current buffer large? */
+ bool is_smb2; /* smb2 not cifs protocol negotiated */
struct delayed_work echo; /* echo ping workqueue job */
struct kvec *iov; /* reusable kvec array for receives */
unsigned int nr_iov; /* number of kvecs in array */
@@ -392,6 +393,9 @@ struct cifs_ses {
negotiate one of the older LANMAN dialects */
#define CIFS_SES_LANMAN 8
#define CIFS_SES_SMB2 16
+
+#define NUMBER_OF_SMB2_COMMANDS 0x0013
+
/*
* there is one of these for each connection to a resource on a particular
* session
@@ -409,27 +413,37 @@ struct cifs_tcon {
enum statusEnum tidStatus;
#ifdef CONFIG_CIFS_STATS
atomic_t num_smbs_sent;
- atomic_t num_writes;
- atomic_t num_reads;
- atomic_t num_flushes;
- atomic_t num_oplock_brks;
- atomic_t num_opens;
- atomic_t num_closes;
- atomic_t num_deletes;
- atomic_t num_mkdirs;
- atomic_t num_posixopens;
- atomic_t num_posixmkdirs;
- atomic_t num_rmdirs;
- atomic_t num_renames;
- atomic_t num_t2renames;
- atomic_t num_ffirst;
- atomic_t num_fnext;
- atomic_t num_fclose;
- atomic_t num_hardlinks;
- atomic_t num_symlinks;
- atomic_t num_locks;
- atomic_t num_acl_get;
- atomic_t num_acl_set;
+ union {
+ struct {
+ atomic_t num_writes;
+ atomic_t num_reads;
+ atomic_t num_flushes;
+ atomic_t num_oplock_brks;
+ atomic_t num_opens;
+ atomic_t num_closes;
+ atomic_t num_deletes;
+ atomic_t num_mkdirs;
+ atomic_t num_posixopens;
+ atomic_t num_posixmkdirs;
+ atomic_t num_rmdirs;
+ atomic_t num_renames;
+ atomic_t num_t2renames;
+ atomic_t num_ffirst;
+ atomic_t num_fnext;
+ atomic_t num_fclose;
+ atomic_t num_hardlinks;
+ atomic_t num_symlinks;
+ atomic_t num_locks;
+ atomic_t num_acl_get;
+ atomic_t num_acl_set;
+ } cifs_stats;
+#ifdef CONFIG_CIFS_SMB2
+ struct {
+ atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
+ atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
+ } smb2_stats;
+#endif /* CONFIG CIFS_SMB2 */
+ } stats;
#ifdef CONFIG_CIFS_STATS2
unsigned long long time_writes;
unsigned long long time_reads;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index ea7b813..4e11051 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -867,7 +867,7 @@ PsxDelete:
cFYI(1, "Posix delete returned %d", rc);
cifs_buf_release(pSMB);
- cifs_stats_inc(&tcon->num_deletes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
if (rc == -EAGAIN)
goto PsxDelete;
@@ -909,7 +909,7 @@ DelFileRetry:
pSMB->ByteCount = cpu_to_le16(name_len + 1);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_deletes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
if (rc)
cFYI(1, "Error in RMFile = %d", rc);
@@ -953,7 +953,7 @@ RmDirRetry:
pSMB->ByteCount = cpu_to_le16(name_len + 1);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_rmdirs);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
if (rc)
cFYI(1, "Error in RMDir = %d", rc);
@@ -996,7 +996,7 @@ MkDirRetry:
pSMB->ByteCount = cpu_to_le16(name_len + 1);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_mkdirs);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
if (rc)
cFYI(1, "Error in Mkdir = %d", rc);
@@ -1118,9 +1118,9 @@ psx_create_err:
cifs_buf_release(pSMB);
if (posix_flags & SMB_O_DIRECTORY)
- cifs_stats_inc(&tcon->num_posixmkdirs);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
else
- cifs_stats_inc(&tcon->num_posixopens);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
if (rc == -EAGAIN)
goto PsxCreat;
@@ -1241,7 +1241,7 @@ OldOpenRetry:
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_opens);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
if (rc) {
cFYI(1, "Error in Open = %d", rc);
} else {
@@ -1354,7 +1354,7 @@ openRetry:
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_opens);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
if (rc) {
cFYI(1, "Error in Open = %d", rc);
} else {
@@ -1728,7 +1728,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
rdata, false);
if (rc == 0)
- cifs_stats_inc(&tcon->num_reads);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
cifs_small_buf_release(smb);
return rc;
@@ -1796,7 +1796,7 @@ CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
&resp_buf_type, CIFS_LOG_ERROR);
- cifs_stats_inc(&tcon->num_reads);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
pSMBr = (READ_RSP *)iov[0].iov_base;
if (rc) {
cERROR(1, "Send error in read = %d", rc);
@@ -1948,7 +1948,7 @@ CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, long_op);
- cifs_stats_inc(&tcon->num_writes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
if (rc) {
cFYI(1, "Send error in write = %d", rc);
} else {
@@ -2197,7 +2197,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
NULL, cifs_writev_callback, wdata, false);
if (rc == 0)
- cifs_stats_inc(&tcon->num_writes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
else
kref_put(&wdata->refcount, cifs_writedata_release);
@@ -2287,7 +2287,7 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
long_op);
- cifs_stats_inc(&tcon->num_writes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
if (rc) {
cFYI(1, "Send error Write2 = %d", rc);
} else if (resp_buf_type == 0) {
@@ -2353,7 +2353,7 @@ int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
iov[1].iov_base = (char *)buf;
iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
- cifs_stats_inc(&tcon->num_locks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
if (rc)
cFYI(1, "Send error in cifs_lockv = %d", rc);
@@ -2422,7 +2422,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
timeout);
/* SMB buffer freed by function above */
}
- cifs_stats_inc(&tcon->num_locks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
if (rc)
cFYI(1, "Send error in Lock = %d", rc);
@@ -2587,7 +2587,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
pSMB->LastWriteTime = 0xFFFFFFFF;
pSMB->ByteCount = 0;
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
- cifs_stats_inc(&tcon->num_closes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
if (rc) {
if (rc != -EINTR) {
/* EINTR is expected when user ctl-c to kill app */
@@ -2616,7 +2616,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
pSMB->FileID = (__u16) smb_file_id;
pSMB->ByteCount = 0;
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
- cifs_stats_inc(&tcon->num_flushes);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
if (rc)
cERROR(1, "Send error in Flush = %d", rc);
@@ -2679,7 +2679,7 @@ renameRetry:
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_renames);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
if (rc)
cFYI(1, "Send error in rename = %d", rc);
@@ -2758,7 +2758,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&pTcon->num_t2renames);
+ cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
if (rc)
cFYI(1, "Send error in Rename (by file handle) = %d", rc);
@@ -2915,7 +2915,7 @@ createSymLinkRetry:
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_symlinks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
if (rc)
cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
@@ -3001,7 +3001,7 @@ createHardLinkRetry:
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_hardlinks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
if (rc)
cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
@@ -3073,7 +3073,7 @@ winCreateHardLinkRetry:
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_hardlinks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
if (rc)
cFYI(1, "Send error in hard link (NT rename) = %d", rc);
@@ -3490,7 +3490,7 @@ queryAclRetry:
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_acl_get);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
if (rc) {
cFYI(1, "Send error in Query POSIX ACL = %d", rc);
} else {
@@ -3801,7 +3801,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
0);
- cifs_stats_inc(&tcon->num_acl_get);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
if (rc) {
cFYI(1, "Send error in QuerySecDesc = %d", rc);
} else { /* decode response */
@@ -4405,7 +4405,7 @@ findFirstRetry:
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_ffirst);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
if (rc) {/* BB add logic to retry regular search if Unix search
rejected unexpectedly by server */
@@ -4532,7 +4532,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_fnext);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
if (rc) {
if (rc == -EBADF) {
psrch_inf->endOfSearch = true;
@@ -4623,7 +4623,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
if (rc)
cERROR(1, "Send error in FindClose = %d", rc);
- cifs_stats_inc(&tcon->num_fclose);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
/* Since session is dead, search handle closed on server already */
if (rc == -EAGAIN)
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 703ef5c..1934575 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
if (tcon->tid != buf->Tid)
continue;
- cifs_stats_inc(&tcon->num_oplock_brks);
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
spin_lock(&cifs_file_list_lock);
list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2) Pavel Shilovsky
` (21 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Steve French
From: Steve French <sfrench@us.ibm.com>
Also set ses->is_smb2 when smb2 session initialized.
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifsglob.h | 1 +
fs/cifs/connect.c | 16 +++++++++++++++-
2 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6dfc7ef..179b784 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -172,6 +172,7 @@ struct smb_vol {
mode_t file_mode;
mode_t dir_mode;
unsigned secFlg;
+ bool use_smb2:1; /* use SMB2 protocol rather that CIFS */
bool retry:1;
bool intr:1;
bool setuids:1;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f70d87d..6743558 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/connect.c
*
- * Copyright (C) International Business Machines Corp., 2002,2009
+ * Copyright (C) International Business Machines Corp., 2002,2011
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -1760,6 +1760,14 @@ static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr,
(struct sockaddr *)&vol->srcaddr))
return 0;
+#ifdef CONFIG_CIFS_SMB2
+ if ((server->is_smb2 == true) && (vol->use_smb2 == false))
+ return 0;
+
+ if ((server->is_smb2 == false) && (vol->use_smb2 == true))
+ return 0;
+#endif /* CONFIG_CIFS_SMB2 */
+
if (!match_port(server, addr))
return 0;
@@ -1884,6 +1892,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
tcp_ses->noblocksnd = volume_info->noblocksnd;
tcp_ses->noautotune = volume_info->noautotune;
+ /* BB should we set this unconditionally now, especially for SMB2 */
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
atomic_set(&tcp_ses->inFlight, 0);
init_waitqueue_head(&tcp_ses->response_q);
@@ -1927,6 +1936,11 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
goto out_err_crypto_release;
}
+#ifdef CONFIG_CIFS_SMB2
+ if (volume_info->use_smb2)
+ tcp_ses->is_smb2 = true;
+#endif /* CONFIG_CIFS_SMB2 */
+
/*
* since we're in a cifs function already, we know that
* this will succeed. No need for try_module_get().
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 04/53] CIFS: Do not try to dump cifs mids from smb2 sessions
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 01/53] CIFS: Update cifs global structures to handle smb2 sessions Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2 Pavel Shilovsky
` (25 subsequent siblings)
27 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Convert the debug routines in cifs_debug.c to recognize
smb2 sessions and not try to dump invalid information on
pending requests. Check the socket type to see if
smb2. Move the printing of cifs specific debug information
to a helper routine to make it clearer which type
of information we are printing.
cifs and smb2 both use the struct TCP_Server_Info to include information about
the tcp socket connection to the server. The list of pending requests
is one of the "per-socket" pieces of information. smb2 and cifs
"mid" queue entries (multiplexed network requests, the active requests
on the wire) differ. smb2 has async support in the protocol,
as well as operation compounding and larger sizes (than cifs) for
various fields related to pending requests) so it is important
not to try to use the pending_mid_q for smb2 tcp sessions
as if it were a pending cifs request. Most usage of the
pending_mid_q is safe because it is in either cifs or smb2
specific code, but this patch fixes the dumping of debug
data so we don't dump cifs debug data for an smb2 session.
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifs_debug.c | 179 +++++++++++++++++++++++++++-----------------------
1 files changed, 98 insertions(+), 81 deletions(-)
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 8ccdb15..add9975 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -72,7 +72,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
struct list_head *tmp;
struct mid_q_entry *mid_entry;
- if (server == NULL)
+ if ((server == NULL) || (server->is_smb2))
return;
cERROR(1, "Dump pending requests:");
@@ -105,16 +105,105 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
#endif /* CONFIG_CIFS_DEBUG2 */
#ifdef CONFIG_PROC_FS
-static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
+
+static void dump_smb2_debug_info(int i, struct seq_file *m,
+ struct TCP_Server_Info *server)
{
- struct list_head *tmp1, *tmp2, *tmp3;
+ seq_printf(m, "dumping debug information for smb2 not supported yet\n");
+}
+
+static void dump_cifs_debug_info(int i, struct seq_file *m,
+ struct TCP_Server_Info *server)
+{
+ struct list_head *tmp2, *tmp3;
struct mid_q_entry *mid_entry;
- struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
- int i, j;
+ int j;
__u32 dev_type;
+
+ list_for_each(tmp2, &server->smb_ses_list) {
+ ses = list_entry(tmp2, struct cifs_ses, smb_ses_list);
+ if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
+ (ses->serverNOS == NULL)) {
+ seq_printf(m, "\n%d) entry for %s not fully "
+ "displayed\n\t", i, ses->serverName);
+ } else {
+ seq_printf(m,
+ "\n%d) Name: %s Domain: %s Uses: %d OS:"
+ " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
+ " session status: %d\t",
+ i, ses->serverName, ses->serverDomain,
+ ses->ses_count, ses->serverOS, ses->serverNOS,
+ ses->capabilities, ses->status);
+ }
+ seq_printf(m, "TCP status: %d\n\tLocal Users To "
+ "Server: %d SecMode: 0x%x Req On Wire: %d",
+ server->tcpStatus, server->srv_count,
+ server->sec_mode,
+ atomic_read(&server->inFlight));
+
+#ifdef CONFIG_CIFS_STATS2
+ seq_printf(m, " In Send: %d In MaxReq Wait: %d",
+ atomic_read(&server->in_send),
+ atomic_read(&server->num_waiters));
+#endif
+
+ seq_puts(m, "\n\tShares:");
+ j = 0;
+ list_for_each(tmp3, &ses->tcon_list) {
+ tcon = list_entry(tmp3, struct cifs_tcon, tcon_list);
+ ++j;
+ dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
+ seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
+ tcon->treeName, tcon->tc_count);
+ if (tcon->nativeFileSystem) {
+ seq_printf(m, "Type: %s ",
+ tcon->nativeFileSystem);
+ }
+ seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
+ "\nPathComponentMax: %d Status: 0x%d",
+ le32_to_cpu(
+ tcon->fsDevInfo.DeviceCharacteristics),
+ le32_to_cpu(tcon->fsAttrInfo.Attributes),
+ le32_to_cpu(
+ tcon->fsAttrInfo.MaxPathNameComponentLength),
+ tcon->tidStatus);
+ if (dev_type == FILE_DEVICE_DISK)
+ seq_puts(m, " type: DISK ");
+ else if (dev_type == FILE_DEVICE_CD_ROM)
+ seq_puts(m, " type: CDROM ");
+ else
+ seq_printf(m, " type: %d ", dev_type);
+
+ if (tcon->need_reconnect)
+ seq_puts(m, "\tDISCONNECTED ");
+ seq_putc(m, '\n');
+ }
+
+ seq_puts(m, "\n\tMIDs:\n");
+
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp3, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp3, struct mid_q_entry, qhead);
+ seq_printf(m, "\tState: %d com: %d pid:"
+ " %d cbdata: %p mid %d\n",
+ mid_entry->midState,
+ (int)mid_entry->command, mid_entry->pid,
+ mid_entry->callback_data,
+ mid_entry->mid);
+ }
+ spin_unlock(&GlobalMid_Lock);
+ }
+}
+
+static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
+{
+ struct list_head *tmp1;
+ struct TCP_Server_Info *server;
+ int i;
+
seq_puts(m,
"Display Internal CIFS Data Structures for Debugging\n"
"---------------------------------------------------\n");
@@ -151,82 +240,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list);
i++;
- list_for_each(tmp2, &server->smb_ses_list) {
- ses = list_entry(tmp2, struct cifs_ses,
- smb_ses_list);
- if ((ses->serverDomain == NULL) ||
- (ses->serverOS == NULL) ||
- (ses->serverNOS == NULL)) {
- seq_printf(m, "\n%d) entry for %s not fully "
- "displayed\n\t", i, ses->serverName);
- } else {
- seq_printf(m,
- "\n%d) Name: %s Domain: %s Uses: %d OS:"
- " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
- " session status: %d\t",
- i, ses->serverName, ses->serverDomain,
- ses->ses_count, ses->serverOS, ses->serverNOS,
- ses->capabilities, ses->status);
- }
- seq_printf(m, "TCP status: %d\n\tLocal Users To "
- "Server: %d SecMode: 0x%x Req On Wire: %d",
- server->tcpStatus, server->srv_count,
- server->sec_mode,
- atomic_read(&server->inFlight));
-
-#ifdef CONFIG_CIFS_STATS2
- seq_printf(m, " In Send: %d In MaxReq Wait: %d",
- atomic_read(&server->in_send),
- atomic_read(&server->num_waiters));
-#endif
-
- seq_puts(m, "\n\tShares:");
- j = 0;
- list_for_each(tmp3, &ses->tcon_list) {
- tcon = list_entry(tmp3, struct cifs_tcon,
- tcon_list);
- ++j;
- dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
- seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
- tcon->treeName, tcon->tc_count);
- if (tcon->nativeFileSystem) {
- seq_printf(m, "Type: %s ",
- tcon->nativeFileSystem);
- }
- seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
- "\nPathComponentMax: %d Status: 0x%d",
- le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
- le32_to_cpu(tcon->fsAttrInfo.Attributes),
- le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
- tcon->tidStatus);
- if (dev_type == FILE_DEVICE_DISK)
- seq_puts(m, " type: DISK ");
- else if (dev_type == FILE_DEVICE_CD_ROM)
- seq_puts(m, " type: CDROM ");
- else
- seq_printf(m, " type: %d ", dev_type);
-
- if (tcon->need_reconnect)
- seq_puts(m, "\tDISCONNECTED ");
- seq_putc(m, '\n');
- }
-
- seq_puts(m, "\n\tMIDs:\n");
-
- spin_lock(&GlobalMid_Lock);
- list_for_each(tmp3, &server->pending_mid_q) {
- mid_entry = list_entry(tmp3, struct mid_q_entry,
- qhead);
- seq_printf(m, "\tState: %d com: %d pid:"
- " %d cbdata: %p mid %d\n",
- mid_entry->midState,
- (int)mid_entry->command,
- mid_entry->pid,
- mid_entry->callback_data,
- mid_entry->mid);
- }
- spin_unlock(&GlobalMid_Lock);
- }
+ if (server->is_smb2)
+ dump_smb2_debug_info(i, m, server);
+ else
+ dump_cifs_debug_info(i, m, server);
}
spin_unlock(&cifs_tcp_ses_lock);
seq_putc(m, '\n');
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2)
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 07/53] CIFS: Add structure definitions for SMB2 PDUs Pavel Shilovsky
` (20 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Steve French
From: Steve French <sfrench@us.ibm.com>
wait_for_free_request is called to ensure that we don't have more than the
configured maximum of requests in flight on the wire (for cifs), but for SMB2,
the number of requests that can be in flight varies dynamically (the client
may request that the server grant more "credits" in a request, and each
request uses at least one credit). Instead of migrating over the original
smb2_wait_for_free_request function, simply add a check in cifs's original
wait_for_free_request for the is_smb2 case to make sure that we don't go
beyond the number of allocated "credits" (ie those that remain from those
the server has allocated for this tcp session). Otherwise the logic is unchanged
(other than to make it extern so that the next function to be added, smb2_sendrcv2
in smbtransport.c can call it - smb2_sendrcv2 will be migrated over in the next patch).
Note that smb2 servers will typically allow many more requests in flight at one time
than cifs servers (which usually default to only 50) and can adjust this as needed.
This should provide significant performance benefit in some workloads (ie smb2
in many cases will get more parallelism than cifs and some other protocols
since some artificially constrain the maximum number of requests).
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifsglob.h | 1 +
fs/cifs/cifsproto.h | 3 ++-
fs/cifs/transport.c | 22 +++++++++++++++++++---
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 179b784..b440329 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -311,6 +311,7 @@ struct TCP_Server_Info {
wait_queue_head_t read_q; /* used by readpages */
atomic_t active_readpage_req; /* used by readpages */
atomic_t resp_rdy; /* used by readpages and demultiplex */
+ atomic_t credits; /* send no more simultaneous requests than this */
__le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
struct task_struct *observe;
char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ef4f631..84d1e4c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsproto.h
*
- * Copyright (c) International Business Machines Corp., 2002,2008
+ * Copyright (c) International Business Machines Corp., 2002,2011
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -68,6 +68,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 int wait_for_free_request(struct TCP_Server_Info *sv, const int long_op);
extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int nvec, mid_receive_t *receive,
mid_callback_t *callback, void *cbdata,
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0cc9584..25d04df 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -254,7 +254,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
return smb_sendv(server, &iov, 1);
}
-static int wait_for_free_request(struct TCP_Server_Info *server,
+int wait_for_free_request(struct TCP_Server_Info *server,
const int long_op)
{
if (long_op == CIFS_ASYNC_OP) {
@@ -265,7 +265,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
spin_lock(&GlobalMid_Lock);
while (1) {
- if (atomic_read(&server->inFlight) >= cifs_max_pending) {
+ if ((server->is_smb2 == false) &&
+ atomic_read(&server->inFlight) >= cifs_max_pending) {
spin_unlock(&GlobalMid_Lock);
cifs_num_waiters_inc(server);
wait_event(server->request_q,
@@ -273,6 +274,16 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
< cifs_max_pending);
cifs_num_waiters_dec(server);
spin_lock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_SMB2
+ } else if (server->is_smb2 &&
+ (atomic_read(&server->credits) < 1)) {
+ spin_unlock(&GlobalMid_Lock);
+ cifs_num_waiters_inc(server);
+ wait_event(server->request_q,
+ atomic_read(&server->credits) > 0);
+ cifs_num_waiters_dec(server);
+ spin_lock(&GlobalMid_Lock);
+#endif /* CONFIG_CIFS_SMB2 */
} else {
if (server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock);
@@ -283,8 +294,13 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
as they are allowed to block on server */
/* update # of requests on the wire to server */
- if (long_op != CIFS_BLOCKING_OP)
+ if (server->is_smb2 == false &&
+ long_op != CIFS_BLOCKING_OP)
atomic_inc(&server->inFlight);
+#ifdef CONFIG_CIFS_SMB2
+ else if (server->is_smb2)
+ atomic_dec(&server->credits);
+#endif
spin_unlock(&GlobalMid_Lock);
break;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 01/53] CIFS: Update cifs global structures to handle smb2 sessions Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 04/53] CIFS: Do not try to dump cifs mids from " Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 10/53] CIFS: Add routines to free SMB2 mids Pavel Shilovsky
` (24 subsequent siblings)
27 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/cifs_unicode.h | 7 +++++
2 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 1b2e180..7f09423 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -330,3 +330,64 @@ ctoUCS_out:
return i;
}
+#ifdef CONFIG_CIFS_SMB2
+/*
+ * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
+ * @from - pointer to input string
+ * @maxbytes - don't go past this many bytes of input string
+ * @codepage - source codepage
+ *
+ * Walk a string and return the number of bytes that the string will
+ * be after being converted to the given charset, not including any null
+ * termination required. Don't walk past maxbytes in the source buffer.
+ */
+
+int
+smb2_local_to_ucs2_bytes(const char *from, int len,
+ const struct nls_table *codepage)
+{
+ int charlen;
+ int i;
+ wchar_t wchar_to;
+
+ if (from == NULL)
+ return 0;
+ for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+ charlen = codepage->char2uni(from, len, &wchar_to);
+ /* Failed conversion defaults to a question mark */
+ if (charlen < 1)
+ charlen = 1;
+ }
+ return 2 * i; /* UCS characters are two bytes */
+}
+
+/*
+ * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
+ * @src - source string
+ * @maxlen - don't walk past this many bytes in the source string
+ * @ucslen - the length of the allocated string in bytes (including null)
+ * @codepage - source codepage
+ *
+ * Take a string convert it from the local codepage to UCS2 and
+ * put it in a new buffer. Returns a pointer to the new string or NULL on
+ * error.
+ */
+__le16 *
+smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
+ const struct nls_table *codepage)
+{
+ int len;
+ __le16 *dst;
+
+ len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
+ len += 2; /* NULL */
+ dst = kmalloc(len, GFP_KERNEL);
+ if (!dst) {
+ *ucs_len = 0;
+ return NULL;
+ }
+ cifs_strtoUCS(dst, src, maxlen, codepage);
+ *ucs_len = len;
+ return dst;
+}
+#endif /* CONFIG_CIFS_SMB2 */
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
index 6d02fd5..e00f677 100644
--- a/fs/cifs/cifs_unicode.h
+++ b/fs/cifs/cifs_unicode.h
@@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
#endif
+#ifdef CONFIG_CIFS_SMB2
+extern int smb2_local_to_ucs2_bytes(const char *from, int len,
+ const struct nls_table *codepage);
+extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
+ int *ucs_len, const struct nls_table *cp);
+#endif /* CONFIG_CIFS_SMB2 */
+
#endif /* _CIFS_UNICODE_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 07/53] CIFS: Add structure definitions for SMB2 PDUs
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (2 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2) Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 09/53] CIFS: Allocating SMB2 mids (multiplex identifier structures) Pavel Shilovsky
` (19 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Steve French
From: Steve French <sfrench@us.ibm.com>
Add structure definitions for SMB2 network operations and globals.
Fixup some compile errors when CONFIG_CIFS_SMB2 manually enabled
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifsglob.h | 7 +-
fs/cifs/cifspdu.h | 2 -
fs/cifs/smb2glob.h | 259 ++++++++++++++
fs/cifs/smb2pdu.h | 997 ++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1260 insertions(+), 5 deletions(-)
create mode 100644 fs/cifs/smb2glob.h
create mode 100644 fs/cifs/smb2pdu.h
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b440329..e2e4acf 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -27,6 +27,9 @@
#include "cifsacl.h"
#include <crypto/internal/hash.h>
#include <linux/scatterlist.h>
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2glob.h"
+#endif /* CONFIG_CIFS_SMB2 */
/*
* The sizes of various internal tables and strings
@@ -314,7 +317,7 @@ struct TCP_Server_Info {
atomic_t credits; /* send no more simultaneous requests than this */
__le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
struct task_struct *observe;
- char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
+/* char smb2_crypt_key[SMB2_CRYPTO_KEY_SIZE]; BB can we use cifs key? */
__u64 current_smb2_mid; /* multiplex id - rotating counter */
__u8 speed; /* helps us identify if this is a slow link */
unsigned int max_read;
@@ -396,8 +399,6 @@ struct cifs_ses {
#define CIFS_SES_LANMAN 8
#define CIFS_SES_SMB2 16
-#define NUMBER_OF_SMB2_COMMANDS 0x0013
-
/*
* there is one of these for each connection to a resource on a particular
* session
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index d1cfc81..3fb03e2 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -428,8 +428,6 @@ struct smb_hdr {
__u8 WordCount;
} __attribute__((packed));
-struct smb2_hdr;
-
/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
static inline void *
BCC(struct smb_hdr *smb)
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
new file mode 100644
index 0000000..44ca68b
--- /dev/null
+++ b/fs/cifs/smb2glob.h
@@ -0,0 +1,259 @@
+/*
+ * fs/cifs/smb2glob.h
+ *
+ * Definitions for various global variables and structures
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2011
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ * Jeremy Allison (jra@samba.org)
+ *
+ * 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.
+ *
+ */
+#ifndef _SMB2_GLOB_H
+#define _SMB2_GLOB_H
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/workqueue.h>
+#include "smb2pdu.h"
+
+/*
+ * The sizes of various internal tables and strings
+ */
+
+#define SMB2_MIN_RCV_POOL 4
+
+
+/*
+ *****************************************************************
+ * Except the SMB2 PDUs themselves all the
+ * globally interesting structs should go here
+ *****************************************************************
+ */
+
+#define SMB2_OBSERVE_CHECK_TIME 20
+#define SMB2_OBSERVE_DELETE_TIME 45
+
+/* Values for tcon->speed set by echo command */
+#define SMB2_ECHO_FAST 1 /* Less than 3 jiffies, 12ms */
+#define SMB2_ECHO_OK 2 /* Less than 15 jiffies, 60ms */
+#define SMB2_ECHO_SLOW 3 /* Less than 125 jiffies, 1/2 sec */
+#define SMB2_ECHO_VERY_SLOW 4 /* Less than 1000 jiffies, 4 seconds */
+#define SMB2_ECHO_TIMEOUT 5 /* Else Too long, server is sick ... */
+
+/*
+ * This info hangs off the smb2_file structure, pointed to by llist.
+ * This is used to track byte stream locks on the file
+ */
+struct smb2_lock {
+ struct list_head llist; /* pointer to next smb2_lock */
+ __u64 offset;
+ __u64 length;
+ __u32 flags;
+};
+
+/*
+ * One of these for each open instance of a file
+ */
+struct smb2_search {
+ loff_t index_of_last_entry;
+ __u16 entries_in_buf;
+ __u32 resume_key;
+ char *ntwrk_buf_start;
+ char *srch_entries_start;
+ char *last_entry;
+ char *presume_name;
+ unsigned int resume_name_len;
+ bool search_end:1;
+ bool empty_dir:1;
+ bool small_buf:1; /* so we know which buf_release function to call */
+};
+
+struct smb2_file {
+ struct list_head tlist; /* pointer to next fid owned by tcon */
+ struct list_head flist; /* next fid (file instance) for this inode */
+ unsigned int uid; /* allows finding which FileInfo structure */
+ __u32 pid; /* process id who opened file */
+ u64 persist_fid;
+ u64 volatile_fid;
+ /* BB add lock scope info here if needed */ ;
+ /* lock scope id (0 if none) */
+ struct dentry *dentry; /* needed for writepage and oplock break */
+ struct mutex lock_mutex;
+ struct list_head llist; /* list of byte range locks we have. */
+ unsigned int f_flags;
+ bool close_pend:1; /* file is marked to close */
+ bool invalid_handle:1; /* file closed via session abend */
+ bool message_mode:1; /* for pipes: message vs byte mode */
+ bool is_dir:1; /* Open directory rather than file */
+ bool oplock_break_cancelled:1;
+ atomic_t count; /* reference count */
+ atomic_t wrt_pending; /* handle in use - defer close */
+ struct work_struct oplock_break; /* work for oplock breaks */
+ struct mutex fh_mutex; /* prevents reopen race after dead ses*/
+ struct smb2_search srch_inf;
+};
+
+/*
+ * One of these for each file inode
+ */
+
+struct smb2_inode {
+ struct list_head lock_list;
+ /* BB add in lists for dirty pages i.e. write caching info for oplock */
+ struct list_head open_file_list;
+ int write_behind_rc;
+ __u32 dos_attrs; /* e.g. DOS archive bit, sparse, compressed, system */
+ __u32 ea_size;
+ unsigned long time; /* jiffies of last update/check of inode */
+ u64 server_eof; /* current file size on server */
+ bool can_cache_read:1; /* read oplock */
+ bool can_cache_all:1; /* read and writebehind oplock */
+ bool can_defer_close:1; /* batch oplock: as above but can defer close */
+ bool oplock_pending:1;
+ bool delete_pending:1; /* DELETE_ON_CLOSE is set */
+ u64 uniqueid; /* server inode number */
+ struct fscache_cookie *fscache;
+ struct inode vfs_inode;
+};
+
+static inline struct smb2_inode *
+SMB2_I(struct inode *inode)
+{
+ return container_of(inode, struct smb2_inode, vfs_inode);
+}
+
+
+static inline void smb2_file_get(struct smb2_file *smb2_file)
+{
+ atomic_inc(&smb2_file->count);
+}
+
+/* Release a reference on the file private data */
+/* BB see file.c cifsFileInfo_put MUSTFIX BB */
+static inline void smb2_file_put(struct smb2_file *smb2_file)
+{
+ if (atomic_dec_and_test(&smb2_file->count)) {
+ iput(smb2_file->dentry->d_inode);
+ kfree(smb2_file);
+ }
+}
+
+/* Represents a read request in page sized blocks.
+ * Used by smb2_readpages().*/
+struct page_req {
+ struct list_head req_node; /* list of page_req's */
+ struct list_head *page_list_index; /* list of pages */
+ struct address_space *mapping;
+ int num_pages;
+ int read_size;
+ int start_page_index; /* first expected index */
+ int end_page_index; /* last expected index */
+ struct mid_q_entry *midq; /* queue structure for demultiplex */
+};
+
+/* one of these for every pending SMB2 request to the server */
+struct smb2_mid_entry {
+ struct list_head qhead; /* mids waiting on reply from this server */
+ __u64 mid; /* multiplex id(s) */
+ __u16 pid; /* process id */
+ __u32 sequence_number; /* for signing */ /* BB check if needed */
+ unsigned long when_alloc; /* when mid was created */
+#ifdef CONFIG_CIFS_STATS2
+ unsigned long when_sent; /* time when smb send finished */
+ unsigned long when_received; /* when demux complete (taken off wire) */
+#endif
+ struct task_struct *tsk; /* task waiting for response */
+ struct smb2_hdr *resp_buf; /* response buffer */
+ char **pagebuf_list; /* response buffer */
+ int num_pages;
+ int mid_state; /* wish this were enum but can not pass to wait_event */
+ __le16 command; /* smb command code */
+ bool async_resp_rcvd:1; /* if server has responded with interim resp */
+ bool large_buf:1; /* if valid response, is pointer to large buf */
+ bool is_kmap_buf:1;
+/* bool multi_rsp:1; BB do we have to account for something in SMB2 like
+ we saw multiple trans2 responses for one request (possible in CIFS) */
+ /* Async things */
+ __u64 *mid_list; /* multiplex id(s) */
+ int *mid_state_list;
+ short int *large_buf_list;
+ unsigned int num_mid;
+ unsigned int act_num_mid;
+ unsigned int num_received;
+ unsigned int cur_id;
+ struct smb2_hdr **resp_buf_list; /* response buffer */
+ __le16 *command_list;
+ bool async:1;
+ bool complex_mid:1; /* complex entry - consists of several messages */
+ int result;
+ unsigned long last_rsp_time;
+ int (*callback)(struct smb2_mid_entry * , void *);
+ void *callback_data;
+};
+
+
+#define SMB2SEC_DEF (SMB2SEC_MAY_SIGN | SMB2SEC_MAY_NTLM | SMB2SEC_MAY_NTLMV2)
+#define SMB2SEC_MAX (SMB2SEC_MUST_SIGN | SMB2SEC_MUST_NTLMV2)
+#define SMB2SEC_AUTH_MASK (SMB2SEC_MAY_NTLM | SMB2SEC_MAY_NTLMV2 | \
+ SMB2SEC_MAY_PLNTXT | SMB2SEC_MAY_KRB5)
+/*
+ *****************************************************************
+ * Constants go here
+ *****************************************************************
+ */
+
+
+/* BB since num credits could be negotiated higher, override with max_pending */
+#define SMB2_MAX_REQ 256
+
+/* Identifiers for functions that use the open, operation, close pattern
+ * in inode.c:open_op_close() */
+#define SMB2_OP_SET_DELETE 1
+#define SMB2_OP_SET_INFO 2
+#define SMB2_OP_QUERY_INFO 3
+#define SMB2_OP_QUERY_DIR 4
+#define SMB2_OP_MKDIR 5
+#define SMB2_OP_RENAME 6
+
+/* Used when constructing chained read requests. */
+#define CHAINED_REQUEST 1
+#define START_OF_CHAIN 2
+#define END_OF_CHAIN 4
+#define RELATED_REQUEST 8
+
+/*
+ * The externs for various global variables put here. The actual declarations
+ * of these should be mostly placed at the front of smb2fs.c to be easy to spot
+ */
+
+
+/*
+ * Global counters, updated atomically
+ */
+extern atomic_t smb2_tcon_reconnect_count;
+
+/* Various Debug counters */
+extern atomic_t smb2_buf_alloc_count; /* current number allocated */
+#ifdef CONFIG_SMB2_STATS2
+extern atomic_t smb2_total_buf_alloc; /* total allocated over all time */
+extern atomic_t smb2_total_smbuf_alloc;
+#endif
+extern atomic_t smb2_smbuf_alloc_count;
+extern atomic_t smb2_mid_count;
+
+/* Misc globals */
+extern unsigned int SMB2_max_buf_size; /* max size not including hdr */
+extern unsigned int smb2_min_rcv; /* min size of big ntwrk buf pool */
+extern unsigned int smb2_min_small; /* min size of small buf pool */
+extern unsigned int smb2_max_pending; /* MAX requests at once to server*/
+
+#endif /* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
new file mode 100644
index 0000000..a24dfdb
--- /dev/null
+++ b/fs/cifs/smb2pdu.h
@@ -0,0 +1,997 @@
+/*
+ * fs/cifs/smb2pdu.h
+ *
+ * Copyright (c) International Business Machines Corp., 2009, 2010
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * 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
+ */
+
+#ifndef _SMB2PDU_H
+#define _SMB2PDU_H
+
+#include <net/sock.h>
+
+#define SMB2_PORT 445
+#define RFC1001_PORT 139
+
+/*
+ * Note that, due to trying to use names similar to the protocol specifications,
+ * there are many mixed case field names in the structures below. Although
+ * this does not match typical Linux kernel style, it is necessary to be
+ * be able to match against the protocol specfication.
+ *
+ * SMB2 commands
+ * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
+ * (ie no useful data other than the SMB error code itself) and are marked such
+ * Knowing this helps avoid response buffer allocations and copy in some cases
+ */
+
+/* List is sent on wire as little endian */
+#define SMB2_NEGOTIATE cpu_to_le16(0x0000)
+#define SMB2_SESSION_SETUP cpu_to_le16(0x0001)
+#define SMB2_LOGOFF cpu_to_le16(0x0002) /* trivial request/resp */
+#define SMB2_TREE_CONNECT cpu_to_le16(0x0003)
+#define SMB2_TREE_DISCONNECT cpu_to_le16(0x0004) /* trivial req/resp */
+#define SMB2_CREATE cpu_to_le16(0x0005)
+#define SMB2_CLOSE cpu_to_le16(0x0006)
+#define SMB2_FLUSH cpu_to_le16(0x0007) /* trivial resp */
+#define SMB2_READ cpu_to_le16(0x0008)
+#define SMB2_WRITE cpu_to_le16(0x0009)
+#define SMB2_LOCK cpu_to_le16(0x000A)
+#define SMB2_IOCTL cpu_to_le16(0x000B)
+#define SMB2_CANCEL cpu_to_le16(0x000C)
+#define SMB2_ECHO cpu_to_le16(0x000D)
+#define SMB2_QUERY_DIRECTORY cpu_to_le16(0x000E)
+#define SMB2_CHANGE_NOTIFY cpu_to_le16(0x000F)
+#define SMB2_QUERY_INFO cpu_to_le16(0x0010)
+#define SMB2_SET_INFO cpu_to_le16(0x0011)
+#define SMB2_OPLOCK_BREAK cpu_to_le16(0x0012)
+
+/* Same List of commands in host endian */
+#define SMB2NEGOTIATE 0x0000
+#define SMB2SESSION_SETUP 0x0001
+#define SMB2LOGOFF 0x0002 /* trivial request/resp */
+#define SMB2TREE_CONNECT 0x0003
+#define SMB2TREE_DISCONNECT 0x0004 /* trivial req/resp */
+#define SMB2CREATE 0x0005
+#define SMB2CLOSE 0x0006
+#define SMB2FLUSH 0x0007 /* trivial resp */
+#define SMB2READ 0x0008
+#define SMB2WRITE 0x0009
+#define SMB2LOCK 0x000A
+#define SMB2IOCTL 0x000B
+#define SMB2CANCEL 0x000C
+#define SMB2ECHO 0x000D
+#define SMB2QUERY_DIRECTORY 0x000E
+#define SMB2CHANGE_NOTIFY 0x000F
+#define SMB2QUERY_INFO 0x0010
+#define SMB2SET_INFO 0x0011
+#define SMB2OPLOCK_BREAK 0x0012
+
+#define NUMBER_OF_SMB2_COMMANDS 0x0013
+
+/* BB FIXME - analyze following three length fields BB */
+#define MAX_SMB2_SMALL_BUFFER_SIZE 460 /* big enough for most */
+#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
+#define SMB2_SMALL_PATH 112 /* allows for one fewer than (460-120)/3 */
+
+/* File Attrubutes */
+
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
+#define FILE_ATTRIBUTE_OFFLINE 0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
+
+/*
+ * SMB2 flag definitions
+ */
+
+#define SMB2FLG_RESPONSE 0x0001 /* this PDU is a response from server */
+
+/*
+ * SMB2 Header Definition
+ *
+ * "MBZ" : Must be Zero
+ * "BB" : BugBug, Something to check/review/analyze later
+ * "PDU" : "Protocol Data Unit" (ie a network "frame")
+ *
+ */
+struct smb2_hdr {
+ __be32 smb2_buf_length; /* big endian on wire */
+ /* length is only two or three bytes - with
+ one or two byte type preceding it that MBZ */
+ __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */
+ __le16 StructureSize; /* 64 */
+ __le16 CreditCharge; /* MBZ */
+ __le32 Status; /* Error from server */
+ __le16 Command;
+ __le16 CreditRequest; /* CreditResponse */
+ __le32 Flags;
+ __le32 NextCommand;
+ __u64 MessageId; /* opaque - so can stay little endian */
+ __le32 ProcessId;
+ __u32 TreeId; /* opaque - so do not make little endian */
+ __u64 SessionId; /* opaque - so do not make little endian */
+ __u8 Signature[16];
+ /* Usually followed by __le16 StructureSize of request or response
+ structure which follows */
+} __attribute__((packed));
+
+struct smb2_async_hdr {
+ __be32 smb2_buf_length; /* big endian on wire */
+ /* length is only two or three bytes - with
+ one or two byte type preceding it that MBZ */
+ __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */
+ __le16 StructureSize; /* 64 */
+ __le16 CreditCharge; /* MBZ */
+ __le32 Status; /* Error from server */
+ __le16 Command;
+ __le16 CreditResponse;
+ __le32 Flags;
+ __le32 NextCommand;
+ __u64 MessageId; /* opaque - so can stay little endian */
+ __u64 AsyncId;
+ __u64 SessionId; /* opaque - so do not make little endian */
+ __u8 Signature[16];
+ /* Usually followed by __le16 StructureSize of request or response
+ structure which follows */
+} __attribute__((packed));
+
+struct smb2_pdu {
+ struct smb2_hdr hdr;
+ __le16 StructureSize2; /* size of wct area (varies, request specific) */
+} __attribute__((packed));
+
+/*
+ * SMB2 flag definitions
+ */
+#define SMB2_FLAGS_SERVER_TO_REDIR cpu_to_le32(0x00000001) /* Response */
+#define SMB2_FLAGS_ASYNC_COMMAND cpu_to_le32(0x00000002)
+#define SMB2_FLAGS_RELATED_OPERATIONS cpu_to_le32(0x00000004)
+#define SMB2_FLAGS_SIGNED cpu_to_le32(0x00000008)
+#define SMB2_FLAGS_DFS_OPERATIONS cpu_to_le32(0x10000000)
+
+/*
+ * Definitions for SMB2 Protocol Data Units (network frames)
+ *
+ * See MS-SMB2.PDF specification for protocol details.
+ * The Naming convention is the lower case version of the SMB2
+ * command code name for the struct. Note that structures must be packed.
+ *
+ */
+struct smb2_err_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize;
+ __le16 Reserved; /* MBZ */
+ __le32 ByteCount; /* even if zero, at least one byte follows */
+ __u8 ErrorData[1]; /* variable length */
+} __attribute__((packed));
+
+/* Symlink error response for error STATUS_STOPPED_ON_SYMLINK
+ Following is the ErrorData structure */
+struct symlink_err_data {
+ __le32 SymLinkLength;
+ __le32 SymLinkErrorTag;
+ __le32 ReparseTag;
+ __le16 ReparseDataLength;
+ __le16 Reserved; /* MBZ */
+ __le16 SubstituteNameOffset;
+ __le16 SubstituteNameLength;
+ __le16 PrintNameOffset;
+ __le16 PrintNameLength;
+ __le32 Flags;
+ __u8 PathBuffer[0]; /* variable length */
+} __attribute__((packed));
+
+struct smb2_negotiate_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 36 */
+ __le16 DialectCount;
+ __le16 SecurityMode;
+ __le16 Reserved; /* MBZ */
+ __le32 Capabilities;
+ __u8 ClientGUID[16]; /* MBZ */
+ __le64 ClientStartTime; /* MBZ */
+ __le16 Dialects[2]; /* variable length */ /* Must include 0x0202 */
+} __attribute__((packed));
+/* SecurityMode flags */
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002
+/* Capabilities flags */
+#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 */
+
+struct smb2_negotiate_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 65 */
+ __le16 SecurityMode;
+ __le16 DialectRevision; /* Should be 0x0202 */
+ __le16 Reserved; /* MBZ */
+ __u8 ServerGUID[16];
+ __le32 Capabilities;
+ __le32 MaxTransactSize;
+ __le32 MaxReadSize;
+ __le32 MaxWriteSize;
+ __le64 SystemTime; /* MBZ */
+ __le64 ServerStartTime;
+ __le16 SecurityBufferOffset;
+ __le16 SecurityBufferLength;
+ __le32 Reserved2; /* may be any value, Ignore */
+ __u8 Buffer[1]; /* variable length GSS security buffer */
+} __attribute__((packed));
+
+struct sess_setup_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 25 */
+ __u8 VcNumber;
+ __u8 SecurityMode;
+ __le32 Capabilities;
+ __le32 Channel;
+ __le16 SecurityBufferOffset;
+ __le16 SecurityBufferLength;
+ __le64 PreviousSessionId;
+ __u8 Buffer[1]; /* variable length GSS security buffer */
+} __attribute__((packed));
+
+/* Currently defined SessionFlags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+struct sess_setup_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 9 */
+ __le16 SessionFlags;
+ __le16 SecurityBufferOffset;
+ __le16 SecurityBufferLength;
+ __u8 Buffer[1]; /* variable length GSS security buffer */
+} __attribute__((packed));
+
+struct logoff_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __le16 Reserved;
+} __attribute__((packed));
+
+struct logoff_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __le16 Reserved;
+} __attribute__((packed));
+
+struct tree_connect_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 9 */
+ __le16 Reserved;
+ __le16 PathOffset;
+ __le16 PathLength;
+ __u8 Buffer[1]; /* variable length */
+} __attribute__((packed));
+
+struct tree_connect_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 16 */
+ __u8 ShareType; /* see below */
+ __u8 Reserved;
+ __le32 ShareFlags; /* see below */
+ __le32 Capabilities; /* see below */
+ __le32 MaximalAccess;
+} __attribute__((packed));
+
+/* Possible ShareType values */
+#define SMB2_SHARE_TYPE_DISK 0x01
+#define SMB2_SHARE_TYPE_PIPE 0x02
+#define SMB2_SHARE_TYPE_PRINT 0x03
+
+/* Possible ShareFlags - exactly one and only one of the first 4 caching flags
+ must be set (any of the remaining, SHI1005, flags may be set individually
+ or in combination */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
+#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
+#define SHI1005_FLAGS_DFS 0x00000001
+#define SHI1005_FLAGS_DFS_ROOT 0x00000002
+#define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS 0x00000100
+#define SHI1005_FLAGS_FORCE_SHARED_DELETE 0x00000200
+#define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x00000400
+#define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
+#define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK 0x00001000
+#define SHI1005_FLAGS_ENABLE_HASH 0x00002000
+
+/* Possible share capabilities */
+#define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008)
+
+struct tree_disconnect_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __le16 Reserved;
+} __attribute__((packed));
+
+struct tree_disconnect_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __le16 Reserved;
+} __attribute__((packed));
+
+/* Oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* Desired Access Flags */
+#define FILE_READ_DATA_LE cpu_to_le32(0x00000001)
+#define FILE_WRITE_DATA_LE cpu_to_le32(0x00000002)
+#define FILE_APPEND_DATA_LE cpu_to_le32(0x00000004)
+#define FILE_READ_EA_LE cpu_to_le32(0x00000008)
+#define FILE_WRITE_EA_LE cpu_to_le32(0x00000010)
+#define FILE_EXECUTE_LE cpu_to_le32(0x00000020)
+#define FILE_READ_ATTRIBUTES_LE cpu_to_le32(0x00000080)
+#define FILE_WRITE_ATTRIBUTES_LE cpu_to_le32(0x00000100)
+#define FILE_DELETE_LE cpu_to_le32(0x00010000)
+#define FILE_READ_CONTROL_LE cpu_to_le32(0x00020000)
+#define FILE_WRITE_DAC_LE cpu_to_le32(0x00040000)
+#define FILE_WRITE_OWNER_LE cpu_to_le32(0x00080000)
+#define FILE_SYNCHRONIZE_LE cpu_to_le32(0x00100000)
+#define FILE_ACCESS_SYSTEM_SECURITY_LE cpu_to_le32(0x01000000)
+#define FILE_MAXIMAL_ACCESS_LE cpu_to_le32(0x02000000)
+#define FILE_GENERIC_ALL_LE cpu_to_le32(0x10000000)
+#define FILE_GENERIC_EXECUTE_LE cpu_to_le32(0x20000000)
+#define FILE_GENERIC_WRITE_LE cpu_to_le32(0x40000000)
+#define FILE_GENERIC_READ_LE cpu_to_le32(0x80000000)
+
+/* ShareAccess Flags */
+#define FILE_SHARE_READ_LE cpu_to_le32(0x00000001)
+#define FILE_SHARE_WRITE_LE cpu_to_le32(0x00000002)
+#define FILE_SHARE_DELETE_LE cpu_to_le32(0x00000004)
+#define FILE_SHARE_ALL_LE cpu_to_le32(0x00000007)
+
+/* CreateDisposition Flags */
+#define FILE_SUPERSEDE_LE cpu_to_le32(0x00000000)
+#define FILE_OPEN_LE cpu_to_le32(0x00000001)
+#define FILE_CREATE_LE cpu_to_le32(0x00000002)
+#define FILE_OPEN_IF_LE cpu_to_le32(0x00000003)
+#define FILE_OVERWRITE_LE cpu_to_le32(0x00000004)
+#define FILE_OVERWRITE_IF_LE cpu_to_le32(0x00000005)
+
+/* CreateOptions Flags */
+#define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001)
+/* same as #define CREATE_NOT_FILE_LE cpu_to_le32(0x00000001) */
+#define FILE_WRITE_THROUGH_LE cpu_to_le32(0x00000002)
+#define FILE_SEQUENTIAL_ONLY_LE cpu_to_le32(0x00000004)
+#define FILE_NO_INTERMEDIATE_BUFFERRING_LE cpu_to_le32(0x00000008)
+#define FILE_SYNCHRONOUS_IO_ALERT_LE cpu_to_le32(0x00000010)
+#define FILE_SYNCHRONOUS_IO_NON_ALERT_LE cpu_to_le32(0x00000020)
+#define FILE_NON_DIRECTORY_FILE_LE cpu_to_le32(0x00000040)
+#define FILE_COMPLETE_IF_OPLOCKED_LE cpu_to_le32(0x00000100)
+#define FILE_NO_EA_KNOWLEDGE_LE cpu_to_le32(0x00000200)
+#define FILE_RANDOM_ACCESS_LE cpu_to_le32(0x00000800)
+#define FILE_DELETE_ON_CLOSE_LE cpu_to_le32(0x00001000)
+#define FILE_OPEN_BY_FILE_ID_LE cpu_to_le32(0x00002000)
+#define FILE_OPEN_FOR_BACKUP_INTENT_LE cpu_to_le32(0x00004000)
+#define FILE_NO_COMPRESSION_LE cpu_to_le32(0x00008000)
+#define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000)
+#define FILE_OPEN_REPARSE_POINT_LE cpu_to_le32(0x00200000)
+#define FILE_OPEN_NO_RECALL_LE cpu_to_le32(0x00400000)
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY_LE cpu_to_le32(0x00800000)
+
+#define FILE_READ_RIGHTS_LE (FILE_READ_DATA_LE | FILE_READ_EA_LE \
+ | FILE_READ_ATTRIBUTES_LE)
+#define FILE_WRITE_RIGHTS_LE (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE \
+ | FILE_WRITE_EA_LE | FILE_WRITE_ATTRIBUTES_LE)
+#define FILE_EXEC_RIGHTS_LE (FILE_EXECUTE_LE)
+
+/* Impersonation Levels */
+#define IL_ANONYMOUS cpu_to_le32(0x00000000)
+#define IL_IDENTIFICATION cpu_to_le32(0x00000001)
+#define IL_IMPERSONATION cpu_to_le32(0x00000002)
+#define IL_DELEGATE cpu_to_le32(0x00000003)
+
+/* Create Context Values */
+#define SMB2_CREATE_EA_BUFFER "ExtA" /* extended attributes */
+#define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */
+#define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ"
+#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC"
+#define SMB2_CREATE_ALLOCATION_SIZE "AlSi"
+#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc"
+#define SMB2_CREATE_TIMEWARP_REQUEST "TWrp"
+#define SMB2_CREATE_QUERY_ON_DISK_ID "QFid"
+#define SMB2_CREATE_REQUEST_LEASE "RqLs"
+
+struct create_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 57 */
+ __u8 SecurityFlags;
+ __u8 RequestedOplockLevel;
+ __le32 ImpersonationLevel;
+ __le64 SmbCreateFlags;
+ __le64 Reserved;
+ __le32 DesiredAccess;
+ __le32 FileAttributes;
+ __le32 ShareAccess;
+ __le32 CreateDisposition;
+ __le32 CreateOptions;
+ __le16 NameOffset;
+ __le16 NameLength;
+ __le32 CreateContextsOffset;
+ __le32 CreateContextsLength;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+struct create_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 89 */
+ __u8 OplockLevel;
+ __u8 Reserved;
+ __le32 CreateAction;
+ __le64 CreationTime;
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le64 AllocationSize;
+ __le64 EndofFile;
+ __le32 FileAttributes;
+ __le32 Reserved2;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __le32 CreateContextsOffset;
+ __le32 CreateContextsLength;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+/* Currently defined values for close flags */
+#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001)
+struct close_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __le16 Flags;
+ __le32 Reserved;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+} __attribute__((packed));
+
+struct close_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* 60 */
+ __le16 Flags;
+ __le32 Reserved;
+ __le64 CreationTime;
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */
+ __le64 EndOfFile;
+ __le32 Attributes;
+} __attribute__((packed));
+
+struct flush_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __le16 Reserved1;
+ __le32 Reserved2;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+} __attribute__((packed));
+
+struct flush_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize;
+ __le16 Reserved;
+} __attribute__((packed));
+
+struct 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];
+} __attribute__((packed));
+
+struct read_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 17 */
+ __u8 DataOffset;
+ __u8 Reserved;
+ __le32 DataLength;
+ __le32 DataRemaining;
+ __u32 Reserved2;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+/* For write request Flags field below the following flag is defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+struct 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];
+} __attribute__((packed));
+
+struct write_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 17 */
+ __u8 DataOffset;
+ __u8 Reserved;
+ __le32 DataLength;
+ __le32 DataRemaining;
+ __u32 Reserved2;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+#define SMB2_LOCKFLAG_SHARED_LOCK 0x0001
+#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x0002
+#define SMB2_LOCKFLAG_UNLOCK 0x0004
+#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0x0010
+
+struct smb2_lock_element {
+ __le64 Offset;
+ __le64 Length;
+ __le16 Flags;
+ __le16 Reserved;
+} __attribute__((packed));
+
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+
+struct smb2_lock_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 48 */
+ __le16 LockCount;
+ __le32 Reserved;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ /* Followed by at least one */
+ struct smb2_lock_element locks[1];
+} __attribute__((packed));
+
+struct smb2_lock_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __le16 Reserved;
+} __attribute__((packed));
+
+struct echo_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __u16 Reserved;
+} __attribute__((packed));
+
+struct echo_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 4 */
+ __u16 Reserved;
+} __attribute__((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 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];
+} __attribute__((packed));
+
+struct query_directory_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 9 */
+ __le16 OutputBufferOffset;
+ __le32 OutputBufferLength;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+/* Possible InfoType values */
+#define SMB2_O_INFO_FILE 0x01
+#define SMB2_O_INFO_FILESYSTEM 0x02
+#define SMB2_O_INFO_SECURITY 0x03
+#define SMB2_O_INFO_QUOTA 0x04
+
+struct query_info_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 41 */
+ __u8 InfoType;
+ __u8 FileInfoClass;
+ __le32 OutputBufferLength;
+ __le16 InputBufferOffset;
+ __u16 Reserved;
+ __le32 InputBufferLength;
+ __le32 AdditionalInformation;
+ __le32 Flags;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+struct query_info_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 9 */
+ __le16 OutputBufferOffset;
+ __le32 OutputBufferLength;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+struct 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];
+} __attribute__((packed));
+
+struct set_info_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 2 */
+} __attribute__((packed));
+
+struct ioctl_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 57 */
+ __le16 Reserved;
+ __le32 Ctlcode;
+ __u64 Fileid[2]; /* persistent and volatile */
+ __le32 Inputoffset;
+ __le32 Inputcount;
+ __le32 Maxinputresp;
+ __le32 Outputoffset;
+ __le32 Outputcount;
+ __le32 Maxoutputresp;
+ __le32 Flags;
+ __le32 Reserved2;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+struct ioctl_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 49 */
+ __le16 Reserved;
+ __le32 Ctlcode;
+ __u64 Fileid[2]; /* persistent and volatile */
+ __le32 Inputoffset;
+ __le32 Inputcount;
+ __le32 Outputoffset;
+ __le32 Outputcount;
+ __le32 Flags;
+ __le32 Reserved2;
+ __u8 Buffer[1];
+} __attribute__((packed));
+
+/*****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+/*
+ * Starting value for maximum SMB size negotiation
+ */
+#define SMB2_MAX_MSGSIZE (4*4096)
+
+
+#define SMB2_NETWORK_OPSYS "SMB2 VFS Client for Linux"
+
+/*
+ * PDU infolevel structure definitions
+ * 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 fs_full_size_info {
+ __le64 TotalAllocationUnits;
+ __le64 CallerAvailableAllocationUnits;
+ __le64 ActualAvailableAllocationUnits;
+ __le32 SectorsPerAllocationUnit;
+ __le32 BytesPerSector;
+};
+
+struct fs_volume_info {
+ __le64 VolumeCreationTime;
+ __le32 VolumeSerialNumber;
+ __le32 VolumeLabelLength;
+ __u8 SupportsObjects; /* 1 = supports object oriented fs objects */
+ __u8 Reserved;
+ /* Variable Length VolumeLabel follows */
+};
+
+struct fs_device_info {
+ __le32 DeviceType; /* see below */
+ __le32 DeviceCharacteristics;
+} __attribute__((packed)); /* device info level 0x104 */
+
+/* DeviceType Flags (remember to endian convert them) */
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+
+#define MAX_FS_NAME 20 /* twice size of longest name ("FAT32") is plenty */
+/* this field is for debugging/informational purposes anyway, so could be
+truncated if extremely long fs names were later created */
+struct fs_attribute_info {
+ __le32 Attributes;
+ __le32 MaximumComponentNameLength;
+ __le32 FileSystemNameLength;
+ char FileSystemName[MAX_FS_NAME]; /* not null terminated */
+} __attribute__((packed));
+
+/* Attributes (remember to endian convert them) */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
+#define FILE_SUPPORTS_TRANSACTIONS 0x00200000
+#define FILE_SUPPORTS_HARD_LINKS 0x00400000
+#define FILE_SUPPORTS_EXTENDED_ATTRS 0x00800000
+#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000
+#define FILE_SUPPORTS_USN_JOURNAL 0x02000000
+
+/* partial list of QUERY INFO levels */
+#define FILE_DIRECTORY_INFORMATION 1
+#define FILE_FULL_DIRECTORY_INFORMATION 2
+#define FILE_BOTH_DIRECTORY_INFORMATION 3
+#define FILE_BASIC_INFORMATION 4
+#define FILE_STANDARD_INFORMATION 5
+#define FILE_INTERNAL_INFORMATION 6
+#define FILE_EA_INFORMATION 7
+#define FILE_ACCESS_INFORMATION 8
+#define FILE_NAME_INFORMATION 9
+#define FILE_RENAME_INFORMATION 10
+#define FILE_LINK_INFORMATION 11
+#define FILE_NAMES_INFORMATION 12
+#define FILE_DISPOSITION_INFORMATION 13
+#define FILE_POSITION_INFORMATION 14
+#define FILE_FULL_EA_INFORMATION 15
+#define FILE_MODE_INFORMATION 16
+#define FILE_ALIGNMENT_INFORMATION 17
+#define FILE_ALL_INFORMATION 18
+#define FILE_ALLOCATION_INFORMATION 19
+#define FILE_END_OF_FILE_INFORMATION 20
+#define FILE_ALTERNATE_NAME_INFORMATION 21
+#define FILE_STREAM_INFORMATION 22
+#define FILE_PIPE_INFORMATION 23
+#define FILE_PIPE_LOCAL_INFORMATION 24
+#define FILE_PIPE_REMOTE_INFORMATION 25
+#define FILE_MAILSLOT_QUERY_INFORMATION 26
+#define FILE_MAILSLOT_SET_INFORMATION 27
+#define FILE_COMPRESSION_INFORMATION 28
+#define FILE_OBJECT_ID_INFORMATION 29
+/* Number 30 not defined in documents */
+#define FILE_MOVE_CLUSTER_INFORMATION 31
+#define FILE_QUOTA_INFORMATION 32
+#define FILE_REPARSE_POINT_INFORMATION 33
+#define FILE_NETWORK_OPEN_INFORMATION 34
+#define FILE_ATTRIBUTE_TAG_INFORMATION 35
+#define FILE_TRACKING_INFORMATION 36
+#define FILEID_BOTH_DIRECTORY_INFORMATION 37
+#define FILEID_FULL_DIRECTORY_INFORMATION 38
+#define FILE_VALID_DATA_LENGTH_INFORMATION 39
+#define FILE_SHORT_NAME_INFORMATION 40
+#define FILE_SFIO_RESERVE_INFORMATION 44
+#define FILE_SFIO_VOLUME_INFORMATION 45
+#define FILE_HARD_LINK_INFORMATION 46
+#define FILE_NORMALIZED_NAME_INFORMATION 48
+#define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
+#define FILE_STANDARD_LINK_INFORMATION 54
+
+struct file_both_directory_info {
+ __le32 next_entry_offset;
+ __u32 file_index;
+ __le64 creation_time;
+ __le64 last_access_time;
+ __le64 last_write_time;
+ __le64 change_time;
+ __le64 end_of_file;
+ __le64 allocation_size;
+ __le32 file_attribute;
+ __le32 filename_length;
+ __le32 easize;
+ __u8 shortname_length;
+ __u8 reserved1;
+ __u8 short_name[24];
+ __u16 reserved2;
+ __le64 file_id;
+ char filename[0];
+} __attribute__((packed));
+
+struct file_full_directory_info {
+ __le32 next_entry_offset;
+ __u32 file_index;
+ __le64 creation_time;
+ __le64 last_access_time;
+ __le64 last_write_time;
+ __le64 change_time;
+ __le64 end_of_file;
+ __le64 allocation_size;
+ __le32 file_attribute;
+ __le32 filename_length;
+ __le32 easize;
+ __u32 reserved2;
+ __le64 file_id;
+ char filename[0];
+} __attribute__((packed));
+
+typedef struct { /* data block encoding of response to level 5 query */
+ __le64 AllocationSize;
+ __le64 EndOfFile; /* size ie offset to first free byte in file */
+ __le32 NumberOfLinks; /* hard links */
+ __u8 DeletePending;
+ __u8 Directory;
+ __u16 Pad2;
+} __attribute__((packed)) FILE_STANDARD_INFO; /* level 5 QPathInfo */
+
+struct FileRenameInformation { /* encoding of request for level 10 */
+ __u8 ReplaceIfExists; /* 1 = replace existing file with new */
+ /* 0 = fail if target file already exists */
+ __u8 Reserved[7];
+ __u64 RootDirectory; /* MBZ for network operations (why says spec?) */
+ __le32 FileNameLength;
+ char FileName[0]; /* New name to be assigned */
+} __attribute__((packed)); /* level 10 set */
+
+struct FileLinkInformation { /* 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 */
+} __attribute__((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
+ CurrentByteOffset */
+typedef struct { /* data block encoding of response to level 18 */
+ __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */
+ __le64 LastAccessTime;
+ __le64 LastWriteTime;
+ __le64 ChangeTime;
+ __le32 Attributes;
+ __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */
+ __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */
+ __le64 EndOfFile; /* size ie offset to first free byte in file */
+ __le32 NumberOfLinks; /* hard links */
+ __u8 DeletePending;
+ __u8 Directory;
+ __u16 Pad2; /* End of FILE_STANDARD_INFO equivalent */
+ __le64 IndexNumber;
+ __le32 EASize;
+ __le32 AccessFlags;
+ __le64 CurrentByteOffset;
+ __le32 Mode;
+ __le32 AlignmentRequirement;
+ __le32 FileNameLength;
+ char FileName[1];
+} __attribute__((packed)) FILE_ALL_INFO_SMB2; /* level 18 Query */
+
+typedef struct { /* data block encoding of request to level 15 */
+ __le64 NextEntryOffset;
+ __u8 EaNameLength;
+ char EaName[1];
+} __attribute__((packed)) FILE_GET_EA_INFO; /* level 15 Query */
+
+typedef struct { /* data block encoding of response to level 15 */
+ __le32 NextEntryOffset;
+ __u8 Flags;
+ __u8 EaNameLength;
+ __le16 EaValueLength;
+ char EaName[1];
+ char EaValue[1];
+} __attribute__((packed)) FILE_FULL_EA_INFO; /* level 15 Query */
+
+/* DFS Flags */ /* BB check if these changed in SMB2 from old transact2
+ get DFS referral flags BB */
+#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
+#define DFSREF_STORAGE_SERVER 0x00000002 /* no further ref requests needed */
+#define DFSREF_TARGET_FAILBACK 0x00000004 /* only for DFS referral version 4 */
+
+/* BB note that various other infolevels are defined in cifspdu.h, although most
+ are obsolete now (for SMB2) or unneeded, some may be useful to move here */
+
+#define SMB2_IOCTL_IS_FSCTL 0x1
+#define SYMLINK_FLAG_RELATIVE 0x1
+#define MS_REPARSE_TAG 0xA000000C
+
+struct symlink_reparse_data_buf {
+ __le32 reparse_tag;
+ __le16 reparse_datalength;
+ __le16 reserved1;
+ __le16 sub_nameoffset;
+ __le16 sub_namelength;
+ __le16 print_nameoffset;
+ __le16 print_namelength;
+ __le32 flags;
+ char pathbuffer[1];
+} __attribute__((packed));
+
+#endif /* _SMB2PDU_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 09/53] CIFS: Allocating SMB2 mids (multiplex identifier structures)
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (3 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 07/53] CIFS: Add structure definitions for SMB2 PDUs Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 15/53] CIFS: Make demultiplex_thread work with SMB2 code Pavel Shilovsky
` (18 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Steve French, Jeff Layton
From: Steve French <sfrench@us.ibm.com>
Multiplex structures track pending requests. Due to protocol
differences including new features, async responses, and
larger sizes to various fields in SMB2 vs. CIFS protocol
(as well as some obsolete features of cifs not needed in
smb2) the structures differ.
Also create routines for allocating smb2 mids
(they are similar in general structure to the two
mid allocation helpers for cifs but with some obvious
differences due to SMB2 protocol).
Thinking over Jeff Layton's comments I have done the following to make
the two types of mid structures clearer:
- removed the now unneeded task field that Jeff noted (for smb2)
- removed the unneded sequence number field for smb2
- reordered the fields in the two mid structures so it is clear what is common
- put the 6 common fields in the two structures are at the beginning (if we
ever would want to move to a common base mid substructure e.g. in a later patch)
- next put the 7 or 8 fields which differ or are protocol unique and used now
- moved to the end, and commented out temporarily (#if 0) until they are used,
the mid fields relating to:
a) handling "async" interim responses from the server to smb2 requests
b) compound multi part operations (smb2 command chaining)
c) those for Pavel's asynchronous smb2_writepages (and Jeremy's readpages)
Next patch will add the routines to delete smb2 mids.
The transport routines (in smb2transport.c) needed by SMB2 Negotiate
obviously need SMB2 mid allocation and deletion routine and will be
added in the next patch after that and will be the first users
of this.
CC: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifsfs.c | 26 +++++++++++++++++-
fs/cifs/cifsglob.h | 12 ++++----
fs/cifs/smb2glob.h | 30 ++++++++++++--------
fs/cifs/smb2proto.h | 2 -
fs/cifs/smb2transport.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 117 insertions(+), 21 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f219dcc..04fd74e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsfs.c
*
- * Copyright (C) International Business Machines Corp., 2002,2008
+ * Copyright (C) International Business Machines Corp., 2002,2011
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
@@ -89,6 +89,11 @@ MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp;
+#ifdef CONFIG_CIFS_SMB2
+extern mempool_t *smb2_mid_poolp;
+mempool_t *smb2_mid_poolp;
+static struct kmem_cache *smb2_mid_cachep;
+#endif /* CONFIG_CIFS_SMB2 */
static int
cifs_read_super(struct super_block *sb)
@@ -1069,6 +1074,25 @@ cifs_init_mids(void)
return -ENOMEM;
}
+#ifdef CONFIG_CIFS_SMB2
+ smb2_mid_cachep = kmem_cache_create("smb2_mpx_ids",
+ sizeof(struct smb2_mid_entry), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (smb2_mid_cachep == NULL) {
+ mempool_destroy(cifs_mid_poolp);
+ kmem_cache_destroy(cifs_mid_cachep);
+ return -ENOMEM;
+ }
+
+ smb2_mid_poolp = mempool_create_slab_pool(3, smb2_mid_cachep);
+ if (smb2_mid_poolp == NULL) {
+ mempool_destroy(cifs_mid_poolp);
+ kmem_cache_destroy(cifs_mid_cachep);
+ kmem_cache_destroy(smb2_mid_cachep);
+ return -ENOMEM;
+ }
+#endif /* CONFIG_CIFS_SMB2 */
+
return 0;
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e2e4acf..2703b7e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -728,9 +728,7 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid);
/* one of these for every pending CIFS request to the server */
struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */
- __u16 mid; /* multiplex id */
- __u16 pid; /* process id */
- __u32 sequence_number; /* for CIFS signing */
+ int midState; /* wish this were enum but can not pass to wait_event */
unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned long when_sent; /* time when smb send finished */
@@ -739,10 +737,12 @@ struct mid_q_entry {
mid_receive_t *receive; /* call receive callback */
mid_callback_t *callback; /* call completion callback */
void *callback_data; /* general purpose pointer for callback */
- struct smb_hdr *resp_buf; /* pointer to received SMB header */
- int midState; /* wish this were enum but can not pass to wait_event */
- __u8 command; /* smb command code */
bool largeBuf:1; /* if valid response, is pointer to large buf */
+ __u16 mid; /* multiplex id */
+ __u32 sequence_number; /* for CIFS signing */
+ __u8 command; /* smb command code */
+ __u16 pid; /* process id */
+ struct smb_hdr *resp_buf; /* response buffer */
bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */
};
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 3d22699..225b250 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -160,29 +160,36 @@ struct page_req {
struct mid_q_entry *midq; /* queue structure for demultiplex */
};
+struct smb2_mid_entry;
+
+typedef void (smb2_mid_callback_t)(struct smb2_mid_entry *mid);
+
/* one of these for every pending SMB2 request to the server */
struct smb2_mid_entry {
struct list_head qhead; /* mids waiting on reply from this server */
- __u64 mid; /* multiplex id(s) */
- __u16 pid; /* process id */
- __u32 sequence_number; /* for signing */ /* BB check if needed */
+ int mid_state; /* wish this were enum but can not pass to wait_event */
unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */
#endif
- struct task_struct *tsk; /* task waiting for response */
+ bool large_buf:1; /* if valid response, is pointer to large buf */
+ smb2_mid_callback_t *callback;
+ void *callback_data;
+ __u64 mid; /* multiplex id(s), bigger for smb2 */
+ __le16 command; /* smb2 command code */
+ __u32 pid; /* process id - bigger for smb2 than cifs */
struct smb2_hdr *resp_buf; /* response buffer */
+
+ /* Additional fields below needed for handling async smb2 responses
+ and for asynchronous smb2_writepages support have been temporarily
+ removed from the port and will be reenabled as that gets merged in */
+
+#if 0 /* Fields needed for smb2_writepages, compound ops, async support */
char **pagebuf_list; /* response buffer */
int num_pages;
- int mid_state; /* wish this were enum but can not pass to wait_event */
- __le16 command; /* smb command code */
bool async_resp_rcvd:1; /* if server has responded with interim resp */
- bool large_buf:1; /* if valid response, is pointer to large buf */
bool is_kmap_buf:1;
-/* bool multi_rsp:1; BB do we have to account for something in SMB2 like
- we saw multiple trans2 responses for one request (possible in CIFS) */
- /* Async things */
__u64 *mid_list; /* multiplex id(s) */
int *mid_state_list;
short int *large_buf_list;
@@ -196,8 +203,7 @@ struct smb2_mid_entry {
bool complex_mid:1; /* complex entry - consists of several messages */
int result;
unsigned long last_rsp_time;
- int (*callback)(struct smb2_mid_entry * , void *);
- void *callback_data;
+#endif
};
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 025362a..c4c40bd 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -187,8 +187,6 @@ extern int new_read_req(struct kvec *iov, struct cifs_tcon *tcon,
const unsigned int count, const __u64 lseek,
unsigned int remaining_bytes,
int request_type);
-extern int allocate_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
- struct mid_q_entry **ppmidq);
extern int smb2_sendv(struct TCP_Server_Info *server, struct kvec *iov,
int n_vec);
extern int smb2_wait_on_complex_mid(struct cifs_ses *ses,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index a8d778c..94b277e 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -35,6 +35,8 @@
#include "cifs_debug.h"
#include "smb2status.h"
+extern mempool_t *smb2_mid_poolp;
+
/*
* Send an (optionally, already signed) SMB2 request over a socket.
* This socket is already locked (by a mutex) by the caller so we
@@ -123,4 +125,70 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
return rc;
}
+static void
+wake_up_smb2_task(struct smb2_mid_entry *mid)
+{
+ wake_up_process(mid->callback_data);
+}
+
+static struct smb2_mid_entry *
+smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
+ struct TCP_Server_Info *server)
+{
+ struct smb2_mid_entry *temp;
+
+ if (server == NULL) {
+ cERROR(1, "Null TCP session in smb2_mid_entry_alloc");
+ return NULL;
+ }
+
+ temp = mempool_alloc(smb2_mid_poolp, GFP_NOFS);
+ if (temp == NULL)
+ return temp;
+ else {
+ memset(temp, 0, sizeof(struct smb2_mid_entry));
+ temp->mid = smb_buffer->MessageId; /* always LE */
+ temp->pid = current->pid;
+ temp->command = smb_buffer->Command; /* Always LE */
+ temp->when_alloc = jiffies;
+
+ /*
+ * The default is for the mid to be synchronous, so the
+ * default callback just wakes up the current task.
+ */
+ temp->callback = wake_up_smb2_task;
+ temp->callback_data = current;
+ }
+
+ atomic_inc(&midCount);
+ temp->mid_state = MID_REQUEST_ALLOCATED;
+ return temp;
+}
+
+static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
+ struct smb2_mid_entry **ppmidQ)
+{
+ if (ses->server->tcpStatus == CifsExiting)
+ return -ENOENT;
+
+ if (ses->server->tcpStatus == CifsNeedReconnect) {
+ cFYI(1, "tcp session dead - return to caller to retry");
+ return -EAGAIN;
+ }
+
+ if (ses->status != CifsGood) {
+ /* check if SMB session is bad because we are setting it up */
+ if ((in_buf->Command != SMB2_SESSION_SETUP) &&
+ (in_buf->Command != SMB2_NEGOTIATE))
+ return -EAGAIN;
+ /* else ok - we are setting up session */
+ }
+ *ppmidQ = smb2_mid_entry_alloc(in_buf, ses->server);
+ if (*ppmidQ == NULL)
+ return -ENOMEM;
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
+ spin_unlock(&GlobalMid_Lock);
+ return 0;
+}
/* BB add missing functions here */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 10/53] CIFS: Add routines to free SMB2 mids
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (2 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 11/53] CIFS: Add sync_smb2_mid_result Pavel Shilovsky
` (23 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Add smb2_mid_entry_free and free_smb2_mid.
These are straightforward and generally similarly
to cifs's DeleteMidQEntry and delete_mid.
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/smb2transport.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 94b277e..59aa1c0 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -191,4 +191,66 @@ static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
spin_unlock(&GlobalMid_Lock);
return 0;
}
+
+static void
+smb2_mid_entry_free(struct smb2_mid_entry *mid_entry)
+{
+#ifdef CONFIG_CIFS_STATS2
+ unsigned long now;
+#endif
+ mid_entry->mid_state = MID_FREE;
+ atomic_dec(&midCount);
+
+ /*
+ * the large buf free will eventually use a different
+ * pool (the cifs size is not optimal for smb2) but
+ * it makes the initial conversion simpler to leave
+ * it using the cifs large buf pool
+ */
+ if (mid_entry->large_buf)
+ cifs_buf_release(mid_entry->resp_buf);
+ else
+ cifs_small_buf_release(mid_entry->resp_buf);
+#ifdef CONFIG_CIFS_STATS2
+ now = jiffies;
+ /*
+ * commands taking longer than one second are indications that
+ * something is wrong, unless it is quite a slow link or server
+ */
+ /*
+ * BB eventually add a mid flag to allow us to indicate other ops such
+ * as SMB2 reads or writes to "offline" files which are ok to be slow
+ */
+ if ((now - mid_entry->when_alloc) > HZ) {
+ if ((cifsFYI & CIFS_TIMER) &&
+ (mid_entry->command != SMB2_LOCK)) {
+ printk(KERN_DEBUG " SMB2 slow rsp: cmd %d mid %lld",
+ mid_entry->command, mid_entry->mid);
+ printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
+ now - mid_entry->when_alloc,
+ now - mid_entry->when_sent,
+ now - mid_entry->when_received);
+ }
+ }
+#endif
+
+ /*
+ * The next two lines or equivalent will be needed when pagebuf support
+ * added back in:
+ if (mid_entry->is_kmap_buf && mid_entry->pagebuf_list)
+ kfree(mid_entry->pagebuf_list);
+ */
+
+ mempool_free(mid_entry, smb2_mid_poolp);
+}
+
+static void
+free_smb2_mid(struct smb2_mid_entry *mid)
+{
+ spin_lock(&GlobalMid_Lock);
+ list_del(&mid->qhead);
+ spin_unlock(&GlobalMid_Lock);
+
+ smb2_mid_entry_free(mid);
+}
/* BB add missing functions here */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 11/53] CIFS: Add sync_smb2_mid_result
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (3 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 10/53] CIFS: Add routines to free SMB2 mids Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 13/53] CIFS: Add SMB2 transport routines Pavel Shilovsky
` (22 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Previously CIFS added a function, sync_mid_result,
to better handle certain error conditions.
This patch adds the equivalent for SMB2 mids (the
functions are used by smb2_sendrcv2
which is added in the next patch)
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/smb2transport.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 59aa1c0..2ca9943 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -244,6 +244,64 @@ smb2_mid_entry_free(struct smb2_mid_entry *mid_entry)
mempool_free(mid_entry, smb2_mid_poolp);
}
+/* This is similar to cifs's wait_for_response but obviously for smb2 mids */
+static int
+wait_for_smb2_response(struct TCP_Server_Info *server,
+ struct smb2_mid_entry *midq)
+{
+ int error;
+
+ error = wait_event_killable(server->response_q,
+ midq->mid_state != MID_REQUEST_SUBMITTED);
+ if (error < 0)
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
+/* This is similar to cifs's sync_mid_result but for smb2 mids */
+static int
+sync_smb2_mid_result(struct smb2_mid_entry *mid, struct TCP_Server_Info *server)
+{
+ int rc = 0;
+
+ cFYI(1, "%s: cmd=%d mid=%lld state=%d", __func__,
+ le16_to_cpu(mid->command), mid->mid, mid->mid_state);
+
+ spin_lock(&GlobalMid_Lock);
+ /* ensure that it's no longer on the pending_mid_q */
+ list_del_init(&mid->qhead);
+
+ switch (mid->mid_state) {
+ case MID_RESPONSE_RECEIVED:
+ spin_unlock(&GlobalMid_Lock);
+ return rc;
+ case MID_REQUEST_SUBMITTED:
+ /* socket is going down, reject all calls */
+ if (server->tcpStatus == CifsExiting) {
+ cERROR(1, "%s: canceling mid=%lld cmd=0x%x state=%d",
+ __func__, mid->mid, le16_to_cpu(mid->command),
+ mid->mid_state);
+ rc = -EHOSTDOWN;
+ break;
+ }
+ case MID_RETRY_NEEDED:
+ rc = -EAGAIN;
+ break;
+ case MID_RESPONSE_MALFORMED:
+ rc = -EIO;
+ break;
+ default:
+ cERROR(1, "%s: invalid mid state mid=%lld state=%d", __func__,
+ mid->mid, mid->mid_state);
+ rc = -EIO;
+ }
+ spin_unlock(&GlobalMid_Lock);
+
+ smb2_mid_entry_free(mid);
+ return rc;
+}
+
static void
free_smb2_mid(struct smb2_mid_entry *mid)
{
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 13/53] CIFS: Add SMB2 transport routines
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (4 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 11/53] CIFS: Add sync_smb2_mid_result Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 14/53] CIFS: Expand cifs mid structure to keep SMB2 related fields Pavel Shilovsky
` (21 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
And simplify smb_sendv to make it process SMB2 requests. It let us
send SMB2 negotiate message to the server.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsglob.h | 6 ++
fs/cifs/cifsproto.h | 4 +-
fs/cifs/smb2misc.c | 11 +--
fs/cifs/smb2proto.h | 4 +-
fs/cifs/smb2transport.c | 209 ++++++++++++++++++++++++++++++++++++++++-------
fs/cifs/transport.c | 75 ++++++++++-------
6 files changed, 240 insertions(+), 69 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 2703b7e..4ccd893 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -239,6 +239,12 @@ struct cifs_mnt_data {
int flags;
};
+static inline unsigned int
+get_rfc1002_length(void *buf)
+{
+ return be32_to_cpu(*((__be32 *)buf));
+}
+
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 2b3fa3b..5109925 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -36,7 +36,9 @@ extern void cifs_buf_release(void *);
extern struct smb_hdr *cifs_small_buf_get(void);
extern void cifs_small_buf_release(void *);
extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
- unsigned int /* length */);
+ unsigned int /* length */);
+extern int smb_sendv(struct TCP_Server_Info *server, struct kvec *iov,
+ int n_vec);
extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int);
#define GetXid() \
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 1a600d8..6f7afdc 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -27,19 +27,18 @@
#include "cifs_unicode.h"
#include "smb2status.h"
-/*
-__u64 get_mid(struct tcp_srv_inf *server)
+__u64 get_mid(struct TCP_Server_Info *server)
{
__u64 mid;
if (server == NULL)
return 0;
- spin_lock(&SMB2_mid_lock);
- mid = server->current_mid++;
- spin_unlock(&SMB2_mid_lock);
+ spin_lock(&GlobalMid_Lock);
+ mid = server->current_smb2_mid++;
+ spin_unlock(&GlobalMid_Lock);
return mid;
-} */ /* BB do we eventually need an SMB2 version of this routine? BB */
+} /* BB do we eventually need an SMB2 version of this routine? BB */
static int
check_smb2_hdr(struct smb2_hdr *smb, __u64 mid)
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index c4c40bd..e826279 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -38,8 +38,8 @@ extern void free_rsp_buf(int resp_buftype, void *pSMB2r);
extern struct smb2_hdr *smb2_buf_get(void);
extern void smb2_buf_release(void *);
extern struct smb2_hdr *smb2_small_buf_get(void);
-extern void smb2_small_buf_release(void *);
-extern __u64 get_mid(struct TCP_Server_Info *server);*/
+extern void smb2_small_buf_release(void *);*/
+extern __u64 get_mid(struct TCP_Server_Info *server);
extern int small_smb2_init_no_tc(__le16 smb2_cmd,
struct cifs_ses *ses,
void **request_buf);
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 2ca9943..adf24c4 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -38,22 +38,15 @@
extern mempool_t *smb2_mid_poolp;
/*
- * Send an (optionally, already signed) SMB2 request over a socket.
- * This socket is already locked (by a mutex) by the caller so we
- * won't have framing problems or mess up SMB2 signatures.
+ * Set message id for the request. Should be called after wait_for_free_response
+ * and locking srv_mutex. iov array must have at least 1 element.
*/
-
-int smb2_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
+static inline void smb2_seq_num_into_buf(struct TCP_Server_Info *server,
+ struct kvec *iov)
{
- int rc = -EHOSTDOWN;
-
- cFYI(1, "function not merged yet"); /* BB fixme */
-
- return rc;
+ ((struct smb2_hdr *)iov[0].iov_base)->MessageId = get_mid(server);
}
-
-
/*
*
* Send an SMB Request. No response info (other than return code)
@@ -108,23 +101,6 @@ smb2_sendrcv_blocking(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
-/*
- * sendrcv2 is passed a cifs_ses structure (rather than simply being
- * passed the ses->server->socket), because it needs the creds
- * contained in the cifs_ses struct in order to sign requests.
- */
-int
-smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
- struct kvec *iov, int n_vec, int *presp_buftype /* ret */,
- int *status /* ret SMB2 network status code */, const int flags)
-{
- int rc = -EHOSTDOWN;
-
- cFYI(1, "function not merged yet"); /* BB fixme */
-
- return rc;
-}
-
static void
wake_up_smb2_task(struct smb2_mid_entry *mid)
{
@@ -251,7 +227,7 @@ wait_for_smb2_response(struct TCP_Server_Info *server,
{
int error;
- error = wait_event_killable(server->response_q,
+ error = wait_event_freezekillable(server->response_q,
midq->mid_state != MID_REQUEST_SUBMITTED);
if (error < 0)
return -ERESTARTSYS;
@@ -311,4 +287,177 @@ free_smb2_mid(struct smb2_mid_entry *mid)
smb2_mid_entry_free(mid);
}
+
+static int
+smb2_check_receive(struct smb2_mid_entry *mid, struct TCP_Server_Info *server,
+ unsigned int receive_len, bool log_error)
+{
+ unsigned int len = get_rfc1002_length(mid->resp_buf);
+
+ dump_smb2(mid->resp_buf, min_t(u32, 80, len));
+ /* convert the length into a more usable form */
+ if ((receive_len > 24) &&
+ (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) {
+ /* BB fixme */
+ /*rc = smb2_verify_signature(mid->resp_buf,
+ &ses->server->mac_signing_key);
+ if (rc) {
+ cERROR(1, "Unexpected SMB signature");
+ } */
+ }
+
+ return map_smb2_to_linux_error(mid->resp_buf, log_error);
+}
+
+/*
+ * sendrcv2 is passed a cifs_ses structure (rather than simply being
+ * passed the ses->server->socket), because it needs the creds
+ * contained in the cifs_ses struct in order to sign requests
+ */
+int
+smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
+ struct kvec *iov, int n_vec, int *presp_buftype /* ret */,
+ int *status /* ret SMB2 network status code */, const int flags)
+{
+ int rc = 0;
+ int long_op;
+ unsigned int receive_len;
+ struct smb2_mid_entry *midQ;
+ struct smb2_hdr *buf = iov[0].iov_base;
+ unsigned int credits = 1;
+
+ if (status)
+ *status = STATUS_SUCCESS;
+ long_op = flags & CIFS_TIMEOUT_MASK;
+
+ *presp_buftype = CIFS_NO_BUFFER; /* no response buf yet */
+
+ if ((ses == NULL) || (ses->server == NULL)) {
+ cifs_small_buf_release(buf);
+ cERROR(1, "Null session");
+ return -EIO;
+ }
+
+ if (ses->server->tcpStatus == CifsExiting) {
+ cifs_small_buf_release(buf);
+ cFYI(1, "ololo");
+ return -ENOENT;
+ }
+
+ rc = wait_for_free_request(ses->server, long_op);
+ if (rc) {
+ cifs_small_buf_release(buf);
+ return rc;
+ }
+
+ /*
+ * Make sure that we sign in the same order that we send on this socket
+ * and avoid races inside tcp sendmsg code that could cause corruption
+ * of smb data.
+ */
+
+ mutex_lock(&ses->server->srv_mutex);
+
+ smb2_seq_num_into_buf(ses->server, iov);
+
+ rc = get_smb2_mid(ses, buf, &midQ);
+ if (rc) {
+ mutex_unlock(&ses->server->srv_mutex);
+ cifs_small_buf_release(buf);
+ atomic_inc(&ses->server->credits);
+ wake_up(&ses->server->request_q);
+ return rc;
+ }
+ /* rc = sign_smb2(iov, n_vec, ses->server); BB
+ if (rc) {
+ mutex_unlock(&ses->server->srv_mutex);
+ cifs_small_buf_release(in_buf);
+ goto out;
+ } */
+
+ midQ->mid_state = MID_REQUEST_SUBMITTED;
+ cifs_in_send_inc(ses->server);
+ rc = smb_sendv(ses->server, iov, n_vec);
+ cifs_in_send_dec(ses->server);
+ cifs_save_when_sent(midQ);
+
+ mutex_unlock(&ses->server->srv_mutex);
+
+ if (rc < 0) {
+ cifs_small_buf_release(buf);
+ goto out;
+ }
+
+ if (long_op == CIFS_ASYNC_OP) {
+ cifs_small_buf_release(buf);
+ goto out;
+ }
+
+ rc = wait_for_smb2_response(ses->server, midQ);
+ if (rc != 0) {
+ /* send_nt_cancel(ses->server, in_buf, midQ); BB */
+ spin_lock(&GlobalMid_Lock);
+ if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
+ midQ->callback = free_smb2_mid;
+ spin_unlock(&GlobalMid_Lock);
+ cifs_small_buf_release(buf);
+ atomic_inc(&ses->server->credits);
+ wake_up(&ses->server->request_q);
+ return rc;
+ }
+ spin_unlock(&GlobalMid_Lock);
+ }
+
+ cifs_small_buf_release(buf);
+
+ rc = sync_smb2_mid_result(midQ, ses->server);
+ if (rc) {
+ atomic_inc(&ses->server->credits);
+ wake_up(&ses->server->request_q);
+ return rc;
+ }
+
+ if (!midQ->resp_buf || (midQ->mid_state != MID_RESPONSE_RECEIVED)) {
+ rc = -EIO;
+ cFYI(1, "Bad MID state?");
+ goto out;
+ }
+
+ buf = (struct smb2_hdr *)midQ->resp_buf;
+ receive_len = be32_to_cpu(buf->smb2_buf_length);
+
+ if (receive_len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) {
+ cERROR(1, "Frame too large received. Length: %d Xid: %d",
+ receive_len, xid);
+ rc = -EIO;
+ goto out;
+ }
+
+ /* rcvd frame is ok */
+
+ iov[0].iov_base = (char *)buf;
+ iov[0].iov_len = receive_len + 4;
+
+ if (midQ->large_buf)
+ *presp_buftype = CIFS_LARGE_BUFFER;
+ else
+ *presp_buftype = CIFS_SMALL_BUFFER;
+
+ rc = smb2_check_receive(midQ, ses->server, receive_len,
+ flags & CIFS_LOG_ERROR);
+
+ if (status)
+ *status = le32_to_cpu(buf->Status);
+
+ if ((flags & CIFS_NO_RESP) == 0)
+ /* mark it so buf will not be freed by free_smb2mid */
+ midQ->resp_buf = NULL;
+
+ credits = le16_to_cpu(buf->CreditRequest);
+out:
+ atomic_add(credits, &ses->server->credits);
+ free_smb2_mid(midQ);
+ wake_up(&ses->server->request_q);
+ return rc;
+}
/* BB add missing functions here */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 25d04df..ee8a1f8 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -120,18 +120,24 @@ delete_mid(struct mid_q_entry *mid)
DeleteMidQEntry(mid);
}
-static int
+int
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
{
int rc = 0;
int i = 0;
struct msghdr smb_msg;
+ __be32 *buf_length = (__be32 *)iov[0].iov_base;
struct smb_hdr *smb_buffer = iov[0].iov_base;
+#ifdef CONFIG_CIFS_SMB2
+ struct smb2_hdr *smb2_buffer = iov[0].iov_base;
+#endif
unsigned int len = iov[0].iov_len;
unsigned int total_len;
int first_vec = 0;
- unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
struct socket *ssocket = server->ssocket;
+ unsigned int smb_buf_length;
+
+ smb_buf_length = get_rfc1002_length(iov[0].iov_base);
if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
@@ -150,7 +156,12 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
total_len += iov[i].iov_len;
cFYI(1, "Sending smb: total_len %d", total_len);
- dump_smb(smb_buffer, len);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ dump_smb2(smb2_buffer, len);
+ else
+#endif
+ dump_smb(smb_buffer, len);
i = 0;
while (total_len) {
@@ -158,24 +169,25 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
n_vec - first_vec, total_len);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++;
- /* if blocking send we try 3 times, since each can block
- for 5 seconds. For nonblocking we have to try more
- but wait increasing amounts of time allowing time for
- socket to clear. The overall time we wait in either
- case to send on the socket is about 15 seconds.
- Similarly we wait for 15 seconds for
- a response from the server in SendReceive[2]
- for the server to send a response back for
- most types of requests (except SMB Write
- past end of file which can be slow, and
- blocking lock operations). NFS waits slightly longer
- than CIFS, but this can make it take longer for
- nonresponsive servers to be detected and 15 seconds
- is more than enough time for modern networks to
- send a packet. In most cases if we fail to send
- after the retries we will kill the socket and
- reconnect which may clear the network problem.
- */
+ /*
+ * If blocking send we try 3 times, since each can block
+ * for 5 seconds. For nonblocking we have to try more
+ * but wait increasing amounts of time allowing time for
+ * socket to clear. The overall time we wait in either
+ * case to send on the socket is about 15 seconds.
+ * Similarly we wait for 15 seconds for
+ * a response from the server in SendReceive[2]
+ * for the server to send a response back for
+ * most types of requests (except SMB Write
+ * past end of file which can be slow, and
+ * blocking lock operations). NFS waits slightly longer
+ * than CIFS, but this can make it take longer for
+ * nonresponsive servers to be detected and 15 seconds
+ * is more than enough time for modern networks to
+ * send a packet. In most cases if we fail to send
+ * after the retries we will kill the socket and
+ * reconnect which may clear the network problem.
+ */
if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
cERROR(1, "sends on sock %p stuck for 15 seconds",
ssocket);
@@ -196,8 +208,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
break;
}
if (rc == 0) {
- /* should never happen, letting socket clear before
- retrying is our only obvious option here */
+ /*
+ * Should never happen, letting socket clear before
+ * retrying is our only obvious option here.
+ */
cERROR(1, "tcp sent no data");
msleep(500);
continue;
@@ -223,10 +237,12 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
cFYI(1, "partial send (%d remaining), terminating session",
total_len);
- /* If we have only sent part of an SMB then the next SMB
- could be taken as the remainder of this one. We need
- to kill the socket so the server throws away the partial
- SMB */
+ /*
+ * If we have only sent part of an SMB then the next SMB
+ * could be taken as the remainder of this one. We need
+ * to kill the socket so the server throws away the partial
+ * SMB.
+ */
server->tcpStatus = CifsNeedReconnect;
}
@@ -235,9 +251,8 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
else
rc = 0;
- /* Don't want to modify the buffer as a
- side effect of this call. */
- smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
+ /* Don't want to modify the buffer as a side effect of this call. */
+ *buf_length = cpu_to_be32(smb_buf_length);
return rc;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 14/53] CIFS: Expand cifs mid structure to keep SMB2 related fields
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (5 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 13/53] CIFS: Add SMB2 transport routines Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 17/53] CIFS: Simplify SMB2 query info Pavel Shilovsky
` (20 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
and let it use the common wait_for_response call.
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifs_debug.c | 13 ++++---
fs/cifs/cifsfs.c | 2 +-
fs/cifs/cifsglob.h | 14 ++++----
fs/cifs/cifsproto.h | 2 +
fs/cifs/cifssmb.c | 12 +++---
fs/cifs/connect.c | 22 ++++++------
fs/cifs/misc.c | 2 +-
fs/cifs/smb2glob.h | 47 ------------------------
fs/cifs/smb2transport.c | 44 +++++++---------------
fs/cifs/transport.c | 93 +++++++++++++++++++++++++----------------------
10 files changed, 98 insertions(+), 153 deletions(-)
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index add9975..1f91bc6 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -79,15 +79,15 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
- mid_entry->midState,
+ cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu",
+ mid_entry->mid_state,
(int)mid_entry->command,
mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
#ifdef CONFIG_CIFS_STATS2
cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
- mid_entry->largeBuf,
+ mid_entry->large_buf,
mid_entry->resp_buf,
mid_entry->when_received,
jiffies);
@@ -188,9 +188,10 @@ static void dump_cifs_debug_info(int i, struct seq_file *m,
list_for_each(tmp3, &server->pending_mid_q) {
mid_entry = list_entry(tmp3, struct mid_q_entry, qhead);
seq_printf(m, "\tState: %d com: %d pid:"
- " %d cbdata: %p mid %d\n",
- mid_entry->midState,
- (int)mid_entry->command, mid_entry->pid,
+ " %d cbdata: %p mid %llu\n",
+ mid_entry->mid_state,
+ le16_to_cpu(mid_entry->command),
+ mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 04fd74e..fce81fc 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1076,7 +1076,7 @@ cifs_init_mids(void)
#ifdef CONFIG_CIFS_SMB2
smb2_mid_cachep = kmem_cache_create("smb2_mpx_ids",
- sizeof(struct smb2_mid_entry), 0,
+ sizeof(struct mid_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL);
if (smb2_mid_cachep == NULL) {
mempool_destroy(cifs_mid_poolp);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4ccd893..a2b14d8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -734,7 +734,7 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid);
/* one of these for every pending CIFS request to the server */
struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */
- int midState; /* wish this were enum but can not pass to wait_event */
+ int mid_state; /* wish this were enum but can not pass to wait_event */
unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned long when_sent; /* time when smb send finished */
@@ -742,13 +742,13 @@ struct mid_q_entry {
#endif
mid_receive_t *receive; /* call receive callback */
mid_callback_t *callback; /* call completion callback */
- void *callback_data; /* general purpose pointer for callback */
- bool largeBuf:1; /* if valid response, is pointer to large buf */
- __u16 mid; /* multiplex id */
+ void *callback_data; /* general purpose pointer for callback */
+ bool large_buf:1; /* if valid response, is pointer to large buf */
+ __u64 mid; /* multiplex id */
+ __le16 command; /* smb command code */
+ __u32 pid; /* process id */
+ void *resp_buf; /* response buffer */
__u32 sequence_number; /* for CIFS signing */
- __u8 command; /* smb command code */
- __u16 pid; /* process id */
- struct smb_hdr *resp_buf; /* response buffer */
bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */
};
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5109925..5a2d6ef 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -71,6 +71,8 @@ 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 int wait_for_free_request(struct TCP_Server_Info *sv, const int long_op);
+extern int wait_for_response(struct TCP_Server_Info *server,
+ struct mid_q_entry *midQ);
extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int nvec, mid_receive_t *receive,
mid_callback_t *callback, void *cbdata,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b029cc7..bc13c8b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1443,7 +1443,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
pgoff_t eof_index;
struct page *page, *tpage;
- cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
+ cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
mid->mid, rdata->offset, rdata->bytes);
/*
@@ -1643,10 +1643,10 @@ cifs_readv_callback(struct mid_q_entry *mid)
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
- cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
- mid->mid, mid->midState, rdata->result, rdata->bytes);
+ cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+ mid->mid, mid->mid_state, rdata->result, rdata->bytes);
- switch (mid->midState) {
+ switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
/* result already set, check signature */
if (server->sec_mode &
@@ -2065,7 +2065,7 @@ cifs_writedata_alloc(unsigned int nr_pages)
}
/*
- * Check the midState and signature on received buffer (if any), and queue the
+ * Check the mid_state and signature on received buffer (if any), and queue the
* workqueue completion task.
*/
static void
@@ -2076,7 +2076,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
unsigned int written;
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
- switch (mid->midState) {
+ switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
if (wdata->result != 0)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 557ba67..680017d 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -144,8 +144,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock);
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- if (mid_entry->midState == MID_REQUEST_SUBMITTED)
- mid_entry->midState = MID_RETRY_NEEDED;
+ if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
+ mid_entry->mid_state = MID_RETRY_NEEDED;
list_move(&mid_entry->qhead, &retry_list);
}
spin_unlock(&GlobalMid_Lock);
@@ -546,8 +546,8 @@ find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
spin_lock(&GlobalMid_Lock);
list_for_each_entry(mid, &server->pending_mid_q, qhead) {
if (mid->mid == buf->Mid &&
- mid->midState == MID_REQUEST_SUBMITTED &&
- mid->command == buf->Command) {
+ mid->mid_state == MID_REQUEST_SUBMITTED &&
+ le16_to_cpu(mid->command) == buf->Command) {
spin_unlock(&GlobalMid_Lock);
return mid;
}
@@ -564,9 +564,9 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
#endif
spin_lock(&GlobalMid_Lock);
if (!malformed)
- mid->midState = MID_RESPONSE_RECEIVED;
+ mid->mid_state = MID_RESPONSE_RECEIVED;
else
- mid->midState = MID_RESPONSE_MALFORMED;
+ mid->mid_state = MID_RESPONSE_MALFORMED;
list_del_init(&mid->qhead);
spin_unlock(&GlobalMid_Lock);
}
@@ -593,13 +593,13 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
} else {
/* Have first buffer */
mid->resp_buf = buf;
- mid->largeBuf = true;
+ mid->large_buf = true;
server->bigbuf = NULL;
}
return;
}
mid->resp_buf = buf;
- mid->largeBuf = server->large_buf;
+ mid->large_buf = server->large_buf;
/* Was previous buf put in mpx struct for multi-rsp? */
if (!mid->multiRsp) {
/* smb buffer will be freed by user thread */
@@ -663,8 +663,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock);
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
- mid_entry->midState = MID_SHUTDOWN;
+ cFYI(1, "Clearing mid 0x%llx", mid_entry->mid);
+ mid_entry->mid_state = MID_SHUTDOWN;
list_move(&mid_entry->qhead, &dispose_list);
}
spin_unlock(&GlobalMid_Lock);
@@ -672,7 +672,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
/* now walk dispose list and issue callbacks */
list_for_each_safe(tmp, tmp2, &dispose_list) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+ cFYI(1, "Callback mid 0x%llx", mid_entry->mid);
list_del_init(&mid_entry->qhead);
mid_entry->callback(mid_entry);
}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 464ebee..4ead6f9 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -264,7 +264,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
++num_mids;
if (mid_entry->mid == server->CurrentMid &&
- mid_entry->midState == MID_REQUEST_SUBMITTED) {
+ mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
/* This mid is in use, try a different one */
collision = true;
break;
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 225b250..0e9fba7 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -160,53 +160,6 @@ struct page_req {
struct mid_q_entry *midq; /* queue structure for demultiplex */
};
-struct smb2_mid_entry;
-
-typedef void (smb2_mid_callback_t)(struct smb2_mid_entry *mid);
-
-/* one of these for every pending SMB2 request to the server */
-struct smb2_mid_entry {
- struct list_head qhead; /* mids waiting on reply from this server */
- int mid_state; /* wish this were enum but can not pass to wait_event */
- unsigned long when_alloc; /* when mid was created */
-#ifdef CONFIG_CIFS_STATS2
- unsigned long when_sent; /* time when smb send finished */
- unsigned long when_received; /* when demux complete (taken off wire) */
-#endif
- bool large_buf:1; /* if valid response, is pointer to large buf */
- smb2_mid_callback_t *callback;
- void *callback_data;
- __u64 mid; /* multiplex id(s), bigger for smb2 */
- __le16 command; /* smb2 command code */
- __u32 pid; /* process id - bigger for smb2 than cifs */
- struct smb2_hdr *resp_buf; /* response buffer */
-
- /* Additional fields below needed for handling async smb2 responses
- and for asynchronous smb2_writepages support have been temporarily
- removed from the port and will be reenabled as that gets merged in */
-
-#if 0 /* Fields needed for smb2_writepages, compound ops, async support */
- char **pagebuf_list; /* response buffer */
- int num_pages;
- bool async_resp_rcvd:1; /* if server has responded with interim resp */
- bool is_kmap_buf:1;
- __u64 *mid_list; /* multiplex id(s) */
- int *mid_state_list;
- short int *large_buf_list;
- unsigned int num_mid;
- unsigned int act_num_mid;
- unsigned int num_received;
- unsigned int cur_id;
- struct smb2_hdr **resp_buf_list; /* response buffer */
- __le16 *command_list;
- bool async:1;
- bool complex_mid:1; /* complex entry - consists of several messages */
- int result;
- unsigned long last_rsp_time;
-#endif
-};
-
-
#define SMB2SEC_DEF (SMB2SEC_MAY_SIGN | SMB2SEC_MAY_NTLM | SMB2SEC_MAY_NTLMV2)
#define SMB2SEC_MAX (SMB2SEC_MUST_SIGN | SMB2SEC_MUST_NTLMV2)
#define SMB2SEC_AUTH_MASK (SMB2SEC_MAY_NTLM | SMB2SEC_MAY_NTLMV2 | \
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index adf24c4..68cbba9 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -102,16 +102,16 @@ smb2_sendrcv_blocking(const unsigned int xid, struct cifs_tcon *tcon,
}
static void
-wake_up_smb2_task(struct smb2_mid_entry *mid)
+wake_up_smb2_task(struct mid_q_entry *mid)
{
wake_up_process(mid->callback_data);
}
-static struct smb2_mid_entry *
+static struct mid_q_entry *
smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
struct TCP_Server_Info *server)
{
- struct smb2_mid_entry *temp;
+ struct mid_q_entry *temp;
if (server == NULL) {
cERROR(1, "Null TCP session in smb2_mid_entry_alloc");
@@ -122,7 +122,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
if (temp == NULL)
return temp;
else {
- memset(temp, 0, sizeof(struct smb2_mid_entry));
+ memset(temp, 0, sizeof(struct mid_q_entry));
temp->mid = smb_buffer->MessageId; /* always LE */
temp->pid = current->pid;
temp->command = smb_buffer->Command; /* Always LE */
@@ -142,7 +142,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
}
static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
- struct smb2_mid_entry **ppmidQ)
+ struct mid_q_entry **ppmidQ)
{
if (ses->server->tcpStatus == CifsExiting)
return -ENOENT;
@@ -169,7 +169,7 @@ static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
}
static void
-smb2_mid_entry_free(struct smb2_mid_entry *mid_entry)
+smb2_mid_entry_free(struct mid_q_entry *mid_entry)
{
#ifdef CONFIG_CIFS_STATS2
unsigned long now;
@@ -220,24 +220,9 @@ smb2_mid_entry_free(struct smb2_mid_entry *mid_entry)
mempool_free(mid_entry, smb2_mid_poolp);
}
-/* This is similar to cifs's wait_for_response but obviously for smb2 mids */
-static int
-wait_for_smb2_response(struct TCP_Server_Info *server,
- struct smb2_mid_entry *midq)
-{
- int error;
-
- error = wait_event_freezekillable(server->response_q,
- midq->mid_state != MID_REQUEST_SUBMITTED);
- if (error < 0)
- return -ERESTARTSYS;
-
- return 0;
-}
-
/* This is similar to cifs's sync_mid_result but for smb2 mids */
static int
-sync_smb2_mid_result(struct smb2_mid_entry *mid, struct TCP_Server_Info *server)
+sync_smb2_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
{
int rc = 0;
@@ -279,7 +264,7 @@ sync_smb2_mid_result(struct smb2_mid_entry *mid, struct TCP_Server_Info *server)
}
static void
-free_smb2_mid(struct smb2_mid_entry *mid)
+free_smb2_mid(struct mid_q_entry *mid)
{
spin_lock(&GlobalMid_Lock);
list_del(&mid->qhead);
@@ -289,7 +274,7 @@ free_smb2_mid(struct smb2_mid_entry *mid)
}
static int
-smb2_check_receive(struct smb2_mid_entry *mid, struct TCP_Server_Info *server,
+smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
unsigned int receive_len, bool log_error)
{
unsigned int len = get_rfc1002_length(mid->resp_buf);
@@ -322,7 +307,7 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
int rc = 0;
int long_op;
unsigned int receive_len;
- struct smb2_mid_entry *midQ;
+ struct mid_q_entry *midQ;
struct smb2_hdr *buf = iov[0].iov_base;
unsigned int credits = 1;
@@ -371,7 +356,7 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
/* rc = sign_smb2(iov, n_vec, ses->server); BB
if (rc) {
mutex_unlock(&ses->server->srv_mutex);
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
goto out;
} */
@@ -393,9 +378,9 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
goto out;
}
- rc = wait_for_smb2_response(ses->server, midQ);
+ rc = wait_for_response(ses->server, midQ);
if (rc != 0) {
- /* send_nt_cancel(ses->server, in_buf, midQ); BB */
+ /* send_nt_cancel(ses->server, buf, midQ); BB */
spin_lock(&GlobalMid_Lock);
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
midQ->callback = free_smb2_mid;
@@ -424,7 +409,7 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
}
buf = (struct smb2_hdr *)midQ->resp_buf;
- receive_len = be32_to_cpu(buf->smb2_buf_length);
+ receive_len = get_rfc1002_length(buf);
if (receive_len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) {
cERROR(1, "Frame too large received. Length: %d Xid: %d",
@@ -437,7 +422,6 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
iov[0].iov_base = (char *)buf;
iov[0].iov_len = receive_len + 4;
-
if (midQ->large_buf)
*presp_buftype = CIFS_LARGE_BUFFER;
else
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index ee8a1f8..bfae7d9 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -60,7 +60,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
memset(temp, 0, sizeof(struct mid_q_entry));
temp->mid = smb_buffer->Mid; /* always LE */
temp->pid = current->pid;
- temp->command = smb_buffer->Command;
+ temp->command = cpu_to_le16(smb_buffer->Command);
cFYI(1, "For smb_command %d", temp->command);
/* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
/* when mid allocated can be before when sent */
@@ -75,7 +75,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
}
atomic_inc(&midCount);
- temp->midState = MID_REQUEST_ALLOCATED;
+ temp->mid_state = MID_REQUEST_ALLOCATED;
return temp;
}
@@ -85,9 +85,9 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
#ifdef CONFIG_CIFS_STATS2
unsigned long now;
#endif
- midEntry->midState = MID_FREE;
+ midEntry->mid_state = MID_FREE;
atomic_dec(&midCount);
- if (midEntry->largeBuf)
+ if (midEntry->large_buf)
cifs_buf_release(midEntry->resp_buf);
else
cifs_small_buf_release(midEntry->resp_buf);
@@ -98,7 +98,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
if ((now - midEntry->when_alloc) > HZ) {
if ((cifsFYI & CIFS_TIMER) &&
(midEntry->command != SMB_COM_LOCKING_ANDX)) {
- printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
+ printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
midEntry->command, midEntry->mid);
printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
now - midEntry->when_alloc,
@@ -351,13 +351,13 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
return 0;
}
-static int
+int
wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
{
int error;
error = wait_event_freezekillable(server->response_q,
- midQ->midState != MID_REQUEST_SUBMITTED);
+ midQ->mid_state != MID_REQUEST_SUBMITTED);
if (error < 0)
return -ERESTARTSYS;
@@ -409,7 +409,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
mid->receive = receive;
mid->callback = callback;
mid->callback_data = cbdata;
- mid->midState = MID_REQUEST_SUBMITTED;
+ mid->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(server);
rc = smb_sendv(server, iov, nvec);
@@ -459,11 +459,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
{
int rc = 0;
- cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
- mid->mid, mid->midState);
+ cFYI(1, "%s: cmd=%d mid=%llu state=%d", __func__, mid->command,
+ mid->mid, mid->mid_state);
spin_lock(&GlobalMid_Lock);
- switch (mid->midState) {
+ switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
spin_unlock(&GlobalMid_Lock);
return rc;
@@ -478,8 +478,8 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
break;
default:
list_del_init(&mid->qhead);
- cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
- mid->mid, mid->midState);
+ cERROR(1, "%s: invalid mid state mid=%llu state=%d", __func__,
+ mid->mid, mid->mid_state);
rc = -EIO;
}
spin_unlock(&GlobalMid_Lock);
@@ -529,7 +529,7 @@ int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
bool log_error)
{
- unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4;
+ unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
dump_smb(mid->resp_buf, min_t(u32, 92, len));
@@ -557,20 +557,20 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
int rc = 0;
int long_op;
struct mid_q_entry *midQ;
- struct smb_hdr *in_buf = iov[0].iov_base;
+ struct smb_hdr *buf = iov[0].iov_base;
long_op = flags & CIFS_TIMEOUT_MASK;
*pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
if ((ses == NULL) || (ses->server == NULL)) {
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
cERROR(1, "Null session");
return -EIO;
}
if (ses->server->tcpStatus == CifsExiting) {
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
return -ENOENT;
}
@@ -580,7 +580,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = wait_for_free_request(ses->server, long_op);
if (rc) {
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
return rc;
}
@@ -590,10 +590,10 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
mutex_lock(&ses->server->srv_mutex);
- rc = allocate_mid(ses, in_buf, &midQ);
+ rc = allocate_mid(ses, buf, &midQ);
if (rc) {
mutex_unlock(&ses->server->srv_mutex);
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
/* Update # of requests on wire to server */
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
@@ -602,11 +602,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
if (rc) {
mutex_unlock(&ses->server->srv_mutex);
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
goto out;
}
- midQ->midState = MID_REQUEST_SUBMITTED;
+ midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(ses->server);
rc = smb_sendv(ses->server, iov, n_vec);
cifs_in_send_dec(ses->server);
@@ -615,23 +615,23 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
mutex_unlock(&ses->server->srv_mutex);
if (rc < 0) {
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
goto out;
}
if (long_op == CIFS_ASYNC_OP) {
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
goto out;
}
rc = wait_for_response(ses->server, midQ);
if (rc != 0) {
- send_nt_cancel(ses->server, in_buf, midQ);
+ send_nt_cancel(ses->server, buf, midQ);
spin_lock(&GlobalMid_Lock);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
@@ -639,7 +639,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
spin_unlock(&GlobalMid_Lock);
}
- cifs_small_buf_release(in_buf);
+ cifs_small_buf_release(buf);
rc = cifs_sync_mid_result(midQ, ses->server);
if (rc != 0) {
@@ -648,15 +648,16 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
return rc;
}
- if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
+ if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
rc = -EIO;
cFYI(1, "Bad MID state?");
goto out;
}
- iov[0].iov_base = (char *)midQ->resp_buf;
- iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
- if (midQ->largeBuf)
+ buf = (struct smb_hdr *)midQ->resp_buf;
+ iov[0].iov_base = (char *)buf;
+ iov[0].iov_len = be32_to_cpu(buf->smb_buf_length) + 4;
+ if (midQ->large_buf)
*pRespBufType = CIFS_LARGE_BUFFER;
else
*pRespBufType = CIFS_SMALL_BUFFER;
@@ -681,6 +682,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
{
int rc = 0;
struct mid_q_entry *midQ;
+ struct smb_hdr *buf;
if (ses == NULL) {
cERROR(1, "Null smb session");
@@ -730,7 +732,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
goto out;
}
- midQ->midState = MID_REQUEST_SUBMITTED;
+ midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(ses->server);
rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
@@ -748,7 +750,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
if (rc != 0) {
send_nt_cancel(ses->server, in_buf, midQ);
spin_lock(&GlobalMid_Lock);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
/* no longer considered to be "in-flight" */
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
@@ -767,14 +769,15 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
}
if (!midQ->resp_buf || !out_buf ||
- midQ->midState != MID_RESPONSE_RECEIVED) {
+ midQ->mid_state != MID_RESPONSE_RECEIVED) {
rc = -EIO;
cERROR(1, "Bad MID state?");
goto out;
}
- *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+ buf = (struct smb_hdr *)midQ->resp_buf;
+ *pbytes_returned = be32_to_cpu(buf->smb_buf_length);
+ memcpy(out_buf, buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, ses->server, 0);
out:
delete_mid(midQ);
@@ -818,6 +821,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
int rstart = 0;
struct mid_q_entry *midQ;
struct cifs_ses *ses;
+ struct smb_hdr *buf;
if (tcon == NULL || tcon->ses == NULL) {
cERROR(1, "Null smb session");
@@ -867,7 +871,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
- midQ->midState = MID_REQUEST_SUBMITTED;
+ midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(ses->server);
rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
cifs_in_send_dec(ses->server);
@@ -881,13 +885,13 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
/* Wait for a reply - allow signals to interrupt. */
rc = wait_event_interruptible(ses->server->response_q,
- (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+ (!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
((ses->server->tcpStatus != CifsGood) &&
(ses->server->tcpStatus != CifsNew)));
/* Were we interrupted by a signal ? */
if ((rc == -ERESTARTSYS) &&
- (midQ->midState == MID_REQUEST_SUBMITTED) &&
+ (midQ->mid_state == MID_REQUEST_SUBMITTED) &&
((ses->server->tcpStatus == CifsGood) ||
(ses->server->tcpStatus == CifsNew))) {
@@ -917,7 +921,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) {
send_nt_cancel(ses->server, in_buf, midQ);
spin_lock(&GlobalMid_Lock);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
/* no longer considered to be "in-flight" */
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
@@ -935,14 +939,15 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
/* rcvd frame is ok */
- if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
+ if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
rc = -EIO;
cERROR(1, "Bad MID state?");
goto out;
}
- *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+ buf = (struct smb_hdr *)midQ->resp_buf;
+ *pbytes_returned = be32_to_cpu(buf->smb_buf_length);
+ memcpy(out_buf, buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, ses->server, 0);
out:
delete_mid(midQ);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 15/53] CIFS: Make demultiplex_thread work with SMB2 code
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (4 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 09/53] CIFS: Allocating SMB2 mids (multiplex identifier structures) Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 16/53] CIFS: Get mount/umount work with SMB2 protocol Pavel Shilovsky
` (17 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Now we can process SMB2 messages: check message, get message id
and wakeup awaiting routines.
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifs_debug.c | 14 ++++-
fs/cifs/connect.c | 161 +++++++++++++++++++++++++++++++++++++++++---------
fs/cifs/misc.c | 5 ++
3 files changed, 151 insertions(+), 29 deletions(-)
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 1f91bc6..b49fed2 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -30,6 +30,9 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifsfs.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
void
cifs_dump_mem(char *label, void *data, int length)
@@ -63,9 +66,18 @@ void cifs_dump_detail(struct smb_hdr *smb)
cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
smb->Command, smb->Status.CifsError,
smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
- cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
+ cERROR(1, "smb buf %p len %u", smb, smbCalcSize(smb));
}
+#ifdef CONFIG_CIFS_SMB2
+void smb2_dump_detail(struct smb2_hdr *smb)
+{
+ cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
+ smb->Command, smb->Status, smb->Flags, smb->MessageId,
+ smb->ProcessId);
+ cERROR(1, "smb buf %p len %u", smb, smb2_calc_size(smb));
+}
+#endif
void cifs_dump_mids(struct TCP_Server_Info *server)
{
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 680017d..ccb7ea7 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -325,6 +325,14 @@ requeue_echo:
static bool
allocate_buffers(struct TCP_Server_Info *server)
{
+ size_t buf_size;
+
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ buf_size = sizeof(struct smb2_hdr);
+ else
+#endif
+ buf_size = sizeof(struct smb_hdr);
if (!server->bigbuf) {
server->bigbuf = (char *)cifs_buf_get();
if (!server->bigbuf) {
@@ -335,7 +343,7 @@ allocate_buffers(struct TCP_Server_Info *server)
}
} else if (server->large_buf) {
/* we are reusing a dirty large buf, clear its start */
- memset(server->bigbuf, 0, sizeof(struct smb_hdr));
+ memset(server->bigbuf, 0, buf_size);
}
if (!server->smallbuf) {
@@ -349,7 +357,7 @@ allocate_buffers(struct TCP_Server_Info *server)
/* beginning of smb buffer is cleared in our buf_get */
} else {
/* if existing small buf clear beginning */
- memset(server->smallbuf, 0, sizeof(struct smb_hdr));
+ memset(server->smallbuf, 0, buf_size);
}
return true;
@@ -539,7 +547,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
}
static struct mid_q_entry *
-find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
+find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
{
struct mid_q_entry *mid;
@@ -556,6 +564,40 @@ find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
return NULL;
}
+#ifdef CONFIG_CIFS_SMB2
+static struct mid_q_entry *
+find_smb2_mid(struct TCP_Server_Info *server, struct smb2_hdr *buf)
+{
+ struct mid_q_entry *mid;
+
+ spin_lock(&GlobalMid_Lock);
+ list_for_each_entry(mid, &server->pending_mid_q, qhead) {
+ if ((mid->mid == buf->MessageId) &&
+ (mid->mid_state == MID_REQUEST_SUBMITTED) &&
+ (mid->command == buf->Command)) {
+ spin_unlock(&GlobalMid_Lock);
+ return mid;
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ return NULL;
+}
+#endif
+
+static struct mid_q_entry *
+find_mid(struct TCP_Server_Info *server, char *buf)
+{
+ struct mid_q_entry *mid;
+
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ mid = find_smb2_mid(server, (struct smb2_hdr *)buf);
+ else
+#endif
+ mid = find_cifs_mid(server, (struct smb_hdr *)buf);
+ return mid;
+}
+
void
dequeue_mid(struct mid_q_entry *mid, bool malformed)
{
@@ -573,13 +615,18 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
static void
handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
- struct smb_hdr *buf, int malformed)
+ char *buf, int malformed)
{
- if (malformed == 0 && check2ndT2(buf) > 0) {
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ goto next;
+#endif
+ if (malformed == 0 && check2ndT2((struct smb_hdr *)buf) > 0) {
mid->multiRsp = true;
if (mid->resp_buf) {
/* merge response - fix up 1st*/
- malformed = coalesce_t2(buf, mid->resp_buf);
+ malformed = coalesce_t2((struct smb_hdr *)buf,
+ mid->resp_buf);
if (malformed > 0)
return;
@@ -598,6 +645,9 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
}
return;
}
+#ifdef CONFIG_CIFS_SMB2
+next:
+#endif
mid->resp_buf = buf;
mid->large_buf = server->large_buf;
/* Was previous buf put in mpx struct for multi-rsp? */
@@ -712,13 +762,27 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
int length;
char *buf = server->smallbuf;
- struct smb_hdr *smb_buffer = (struct smb_hdr *)buf;
- unsigned int pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+ unsigned int pdu_length = get_rfc1002_length(buf);
+ size_t buf_size, max_hdr_size;
+ struct smb_hdr *smb_buffer = (struct smb_hdr *)buf; /* quiet compiler */
+#ifdef CONFIG_CIFS_SMB2
+ struct smb2_hdr *smb2_buffer = (struct smb2_hdr *)buf;
+#endif
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2) {
+ max_hdr_size = MAX_SMB2_HDR_SIZE;
+ buf_size = sizeof(struct smb2_hdr);
+ } else {
+#endif
+ max_hdr_size = MAX_CIFS_HDR_SIZE;
+ buf_size = sizeof(struct smb_hdr);
+#ifdef CONFIG_CIFS_SMB2
+ }
+#endif
/* make sure this will fit in a large buffer */
- if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- cERROR(1, "SMB response too long (%u bytes)",
- pdu_length);
+ if (pdu_length > CIFSMaxBufSize + max_hdr_size - 4) {
+ cERROR(1, "SMB response too long (%u bytes)", pdu_length);
cifs_reconnect(server);
wake_up(&server->response_q);
return -EAGAIN;
@@ -729,18 +793,27 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
server->large_buf = true;
memcpy(server->bigbuf, server->smallbuf, server->total_read);
buf = server->bigbuf;
- smb_buffer = (struct smb_hdr *)buf;
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ smb2_buffer = (struct smb2_hdr *)buf;
+ else
+#endif
+ smb_buffer = (struct smb_hdr *)buf;
}
/* now read the rest */
- length = cifs_read_from_socket(server,
- buf + sizeof(struct smb_hdr) - 1,
- pdu_length - sizeof(struct smb_hdr) + 1 + 4);
+ length = cifs_read_from_socket(server, buf + buf_size - 1,
+ pdu_length - buf_size + 1 + 4);
if (length < 0)
return length;
server->total_read += length;
- dump_smb(smb_buffer, server->total_read);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ dump_smb2(smb2_buffer, server->total_read);
+ else
+#endif
+ dump_smb(smb_buffer, server->total_read);
/*
* We know that we received enough to get to the MID as we
@@ -751,13 +824,20 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
* 48 bytes is enough to display the header and a little bit
* into the payload for debugging purposes.
*/
- length = checkSMB(smb_buffer, smb_buffer->Mid, server->total_read);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ length = checkSMB2(smb2_buffer, smb2_buffer->MessageId,
+ server->total_read);
+ else
+#endif
+ length = checkSMB(smb_buffer, smb_buffer->Mid,
+ server->total_read);
if (length != 0)
cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, server->total_read, 48));
if (mid)
- handle_mid(mid, server, smb_buffer, length);
+ handle_mid(mid, server, buf, length);
return length;
}
@@ -769,7 +849,11 @@ cifs_demultiplex_thread(void *p)
struct TCP_Server_Info *server = p;
unsigned int pdu_length;
char *buf = NULL;
+ size_t buf_size;
struct smb_hdr *smb_buffer = NULL;
+#ifdef CONFIG_CIFS_SMB2
+ struct smb2_hdr *smb2_buffer = NULL;
+#endif
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
@@ -781,6 +865,13 @@ cifs_demultiplex_thread(void *p)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ buf_size = sizeof(struct smb2_hdr);
+ else
+#endif
+ buf_size = sizeof(struct smb_hdr);
+
set_freezable();
while (server->tcpStatus != CifsExiting) {
if (try_to_freeze())
@@ -790,8 +881,13 @@ cifs_demultiplex_thread(void *p)
continue;
server->large_buf = false;
- smb_buffer = (struct smb_hdr *)server->smallbuf;
buf = server->smallbuf;
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ smb2_buffer = (struct smb2_hdr *)buf;
+ else
+#endif
+ smb_buffer = (struct smb_hdr *)buf;
pdu_length = 4; /* enough to get RFC1001 header */
length = cifs_read_from_socket(server, buf, pdu_length);
@@ -803,14 +899,14 @@ cifs_demultiplex_thread(void *p)
* The right amount was read from socket - 4 bytes,
* so we can now interpret the length field.
*/
- pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+ pdu_length = get_rfc1002_length(buf);
cFYI(1, "RFC1002 header 0x%x", pdu_length);
if (!is_smb_response(server, buf[0]))
continue;
/* make sure we have enough to get to the MID */
- if (pdu_length < sizeof(struct smb_hdr) - 1 - 4) {
+ if (pdu_length < buf_size - 1 - 4) {
cERROR(1, "SMB response too short (%u bytes)",
pdu_length);
cifs_reconnect(server);
@@ -820,12 +916,12 @@ cifs_demultiplex_thread(void *p)
/* read down to the MID */
length = cifs_read_from_socket(server, buf + 4,
- sizeof(struct smb_hdr) - 1 - 4);
+ buf_size - 1 - 4);
if (length < 0)
continue;
server->total_read += length;
- mid_entry = find_mid(server, smb_buffer);
+ mid_entry = find_mid(server, buf);
if (!mid_entry || !mid_entry->receive)
length = standard_receive3(server, mid_entry);
@@ -837,20 +933,29 @@ cifs_demultiplex_thread(void *p)
if (server->large_buf) {
buf = server->bigbuf;
- smb_buffer = (struct smb_hdr *)buf;
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ smb2_buffer = (struct smb2_hdr *)buf;
+ else
+#endif
+ smb_buffer = (struct smb_hdr *)buf;
}
server->lstrp = jiffies;
if (mid_entry != NULL) {
if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry);
- } else if (!is_valid_oplock_break(smb_buffer, server)) {
+ } else if (!is_valid_oplock_break((void *)buf, server)) {
cERROR(1, "No task to wake, unknown frame received! "
"NumMids %d", atomic_read(&midCount));
- cifs_dump_mem("Received Data is: ", buf,
- sizeof(struct smb_hdr));
+ cifs_dump_mem("Received Data is: ", buf, buf_size);
#ifdef CONFIG_CIFS_DEBUG2
- cifs_dump_detail(smb_buffer);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ smb2_dump_detail(smb2_buffer);
+ else
+#endif
+ cifs_dump_detail(smb_buffer);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 4ead6f9..d291463 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -514,6 +514,11 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
struct cifsInodeInfo *pCifsInode;
struct cifsFileInfo *netfile;
+#ifdef CONFIG_CIFS_SMB2
+ if (srv->is_smb2)
+ return false;
+#endif
+
cFYI(1, "Checking for oplock break or dnotify response");
if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
(pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 16/53] CIFS: Get mount/umount work with SMB2 protocol
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (5 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 15/53] CIFS: Make demultiplex_thread work with SMB2 code Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 18/53] CIFS: Add SMB2 inode/dentry ops structures Pavel Shilovsky
` (16 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Process SMB2 session setup, tree connect, getting inode info,
tree disconnect and logoff messages.
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/connect.c | 107 ++++++++++++++++++++++++++++++++----------
fs/cifs/inode.c | 132 +++++++++++++++++++++++++++++++++++++++++++---------
fs/cifs/smb2sess.c | 2 +
3 files changed, 194 insertions(+), 47 deletions(-)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ccb7ea7..0187f11 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -99,6 +99,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock);
server->maxBuf = 0;
+#ifdef CONFIG_CIFS_SMB2
+ server->max_read = 0;
+#endif
cFYI(1, "Reconnecting tcp session");
@@ -313,7 +316,13 @@ cifs_echo_request(struct work_struct *work)
time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
goto requeue_echo;
- rc = CIFSSMBEcho(server);
+ if (server->is_smb2 == false)
+ rc = CIFSSMBEcho(server);
+#ifdef CONFIG_CIFS_SMB2
+ else /*temporarilly disable echo requests for smb2
+ rc = SMB2_echo(server); */
+ rc = 0;
+#endif
if (rc)
cFYI(1, "Unable to send echo request to server: %s",
server->hostname);
@@ -2151,7 +2160,12 @@ cifs_put_smb_ses(struct cifs_ses *ses)
if (ses->status == CifsGood) {
xid = GetXid();
- CIFSSMBLogoff(xid, ses);
+#ifdef CONFIG_CIFS_SMB2
+ if (ses->server->is_smb2)
+ SMB2_logoff(xid, ses);
+ else
+#endif
+ CIFSSMBLogoff(xid, ses);
_FreeXid(xid);
}
sesInfoFree(ses);
@@ -2312,7 +2326,12 @@ cifs_put_tcon(struct cifs_tcon *tcon)
spin_unlock(&cifs_tcp_ses_lock);
xid = GetXid();
- CIFSSMBTDis(xid, tcon);
+#ifdef CONFIG_CIFS_SMB2
+ if (ses->server->is_smb2)
+ SMB2_tdis(xid, tcon);
+ else
+#endif
+ CIFSSMBTDis(xid, tcon);
_FreeXid(xid);
cifs_fscache_release_super_cookie(tcon);
@@ -2323,7 +2342,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
static struct cifs_tcon *
cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
{
- int rc, xid;
+ int rc = 0, xid;
struct cifs_tcon *tcon;
tcon = cifs_find_tcon(ses, volume_info->UNC);
@@ -2363,7 +2382,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect? */
xid = GetXid();
- rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls);
+#ifdef CONFIG_CIFS_SMB2
+ if (ses->server->is_smb2)
+ rc = SMB2_tcon(xid, ses, volume_info->UNC, tcon,
+ volume_info->local_nls);
+ else
+#endif
+ rc = CIFSTCon(xid, ses, volume_info->UNC, tcon,
+ volume_info->local_nls);
FreeXid(xid);
cFYI(1, "CIFS Tcon rc = %d", rc);
if (rc)
@@ -2518,6 +2544,12 @@ get_dfs_path(int xid, struct cifs_ses *pSesInfo, const char *old_path,
char *temp_unc;
int rc = 0;
+#ifdef CONFIG_CIFS_SMB2
+ if (pSesInfo->server->is_smb2) {
+ /* add missing smb2 dfs code here */
+ return -EREMOTE;
+ }
+#endif
*pnum_referrals = 0;
*preferrals = NULL;
@@ -3116,22 +3148,38 @@ is_path_accessible(int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path)
{
int rc;
- FILE_ALL_INFO *pfile_info;
-
- pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
- if (pfile_info == NULL)
- return -ENOMEM;
- rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
- 0 /* not legacy */, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2) {
+ __u64 persistent_fid, volatile_fid;
+ rc = SMB2_open(xid, tcon, (__le16 *)full_path, &persistent_fid,
+ &volatile_fid, FILE_READ_ATTRIBUTES, FILE_OPEN,
+ 0, 0);
+ if (rc)
+ return rc;
+ /* rc = SMB2_query_info() */
+ rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+ } else {
+#endif
+ FILE_ALL_INFO *pfile_info = kmalloc(sizeof(FILE_ALL_INFO),
+ GFP_KERNEL);
+ if (pfile_info == NULL)
+ return -ENOMEM;
- if (rc == -EOPNOTSUPP || rc == -EINVAL)
- rc = SMBQueryInformation(xid, tcon, full_path, pfile_info,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- kfree(pfile_info);
+ rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
+ 0 /* not legacy */, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ if (rc == -EOPNOTSUPP || rc == -EINVAL)
+ rc = SMBQueryInformation(xid, tcon, full_path,
+ pfile_info, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ kfree(pfile_info);
+#ifdef CONFIG_CIFS_SMB2
+ }
+#endif
return rc;
}
@@ -3397,10 +3445,18 @@ try_mount_again:
tcon->unix_ext = 0; /* server does not support them */
/* do not care if following two calls succeed - informational */
- if (!tcon->ipc) {
- CIFSSMBQFSDeviceInfo(xid, tcon);
- CIFSSMBQFSAttributeInfo(xid, tcon);
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2) {
+ /* add missing calls here */
+ } else {
+#endif
+ if (!tcon->ipc) {
+ CIFSSMBQFSDeviceInfo(xid, tcon);
+ CIFSSMBQFSAttributeInfo(xid, tcon);
+ }
+#ifdef CONFIG_CIFS_SMB2
}
+#endif
cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
@@ -3718,6 +3774,7 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
if (ses->server->is_smb2) {
/* we have one credit to start with */
atomic_set(&server->credits, 1);
+ server->current_smb2_mid = 0;
rc = SMB2_negotiate(xid, ses);
/* BB we probably don't need to retry with modern servers */
if (rc == -EAGAIN)
@@ -3766,12 +3823,12 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
server->sec_mode, server->capabilities, server->timeAdj);
- if (ses->server->is_smb2 == false)
- rc = CIFS_SessSetup(xid, ses, nls_info);
#ifdef CONFIG_CIFS_SMB2
- else
+ if (ses->server->is_smb2)
rc = SMB2_sess_setup(xid, ses, nls_info);
+ else
#endif
+ rc = CIFS_SessSetup(xid, ses, nls_info);
if (rc) {
cERROR(1, "Send error in SessSetup = %d", rc);
} else {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 2c50bd2..4d03038 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -29,8 +29,11 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
#include "fscache.h"
-
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
static void cifs_set_ops(struct inode *inode)
{
@@ -595,9 +598,68 @@ cgfi_exit:
return rc;
}
-int cifs_get_inode_info(struct inode **pinode,
- const unsigned char *full_path, FILE_ALL_INFO *pfindData,
- struct super_block *sb, int xid, const __u16 *pfid)
+#ifdef CONFIG_CIFS_SMB2
+static void
+move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src)
+{
+ memcpy(dst, src,
+ (unsigned int)(&src->CurrentByteOffset) - (unsigned int)src);
+ dst->CurrentByteOffset = src->CurrentByteOffset;
+ dst->Mode = src->Mode;
+ dst->AlignmentRequirement = src->AlignmentRequirement;
+ dst->IndexNumber1 = 0; /* we don't use it */
+}
+
+static int
+smb2_qinfo_helper(int xid, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ const unsigned char *full_path, FILE_ALL_INFO *pfindData)
+{
+ const unsigned char *start_full_path = full_path;
+ __u64 persistent_fid, volatile_fid;
+ FILE_ALL_INFO_SMB2 *data = NULL;
+ __le16 *path = NULL;
+ int usc_len, rc;
+
+ data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2, GFP_KERNEL);
+ if (data == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (strlen(full_path) && full_path[0] == '\\')
+ start_full_path += 1;
+
+ path = smb2_strndup_to_ucs(start_full_path,
+ PATH_MAX, &usc_len,
+ cifs_sb->local_nls);
+ if (path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = SMB2_open(xid, tcon, path, &persistent_fid, &volatile_fid,
+ FILE_READ_ATTRIBUTES_LE, FILE_OPEN_LE, 0, 0);
+ if (!rc) {
+ rc = SMB2_query_info(xid, tcon, persistent_fid,
+ volatile_fid, data);
+ SMB2_close(xid, tcon, persistent_fid,
+ volatile_fid);
+ }
+
+ if (rc)
+ goto out;
+
+ move_smb2_info_to_cifs(pfindData, data);
+out:
+ kfree(data);
+ kfree(path);
+ return rc;
+}
+#endif
+
+int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
+ FILE_ALL_INFO *pfindData, struct super_block *sb,
+ int xid, const __u16 *pfid)
{
int rc = 0, tmprc;
struct cifs_tcon *pTcon;
@@ -630,21 +692,36 @@ int cifs_get_inode_info(struct inode **pinode,
}
pfindData = (FILE_ALL_INFO *)buf;
- /* could do find first instead but this returns more info */
- rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
- 0 /* not legacy */,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- /* BB optimize code so we do not make the above call
- when server claims no NT SMB support and the above call
- failed at least once - set flag in tcon or mount */
- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
- rc = SMBQueryInformation(xid, pTcon, full_path,
- pfindData, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- adjustTZ = true;
+ if (pTcon->ses->server->is_smb2 == false) {
+ /*
+ * Could do find first instead but this returns more
+ * info.
+ */
+ rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
+ 0 /* not legacy */,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ /*
+ * BB optimize code so we do not make the above call
+ * when server claims no NT SMB support and the above
+ * call failed at least once - set flag in tcon or
+ * mount.
+ */
+ if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+ rc = SMBQueryInformation(xid, pTcon, full_path,
+ pfindData, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ adjustTZ = true;
+ }
+#ifdef CONFIG_CIFS_SMB2
+ } else
+ rc = smb2_qinfo_helper(xid, cifs_sb, pTcon, full_path,
+ pfindData);
+#else
}
+#endif
}
if (!rc) {
@@ -675,7 +752,8 @@ int cifs_get_inode_info(struct inode **pinode,
* guaranteed unique?
*/
if (*pinode == NULL) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
+ pTcon->ses->server->is_smb2 == false) {
int rc1 = 0;
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
@@ -754,12 +832,22 @@ char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
/* if no prefix path, simply set path to the root of share to "" */
if (pplen == 0) {
- full_path = kmalloc(1, GFP_KERNEL);
- if (full_path)
- full_path[0] = 0;
+ int len = 1;
+#ifdef CONFIG_CIFS_SMB2
+ if (vol->use_smb2)
+ len = 2;
+#endif
+ full_path = kzalloc(len, GFP_KERNEL);
return full_path;
}
+#ifdef CONFIG_CIFS_SMB2
+ if (vol->use_smb2) {
+ cERROR(1, "prefixpath is not supported for smb2 now");
+ return NULL;
+ }
+#endif
+
if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
else
diff --git a/fs/cifs/smb2sess.c b/fs/cifs/smb2sess.c
index 440fe0b..5e51eb4 100644
--- a/fs/cifs/smb2sess.c
+++ b/fs/cifs/smb2sess.c
@@ -39,10 +39,12 @@ int smb2_setup_session(unsigned int xid, struct cifs_ses *psesinfo,
*/
if (server->max_read == 0) /* no need to send on reconnect */ {
atomic_set(&server->credits, 1);
+ server->current_smb2_mid = 0;
rc = SMB2_negotiate(xid, psesinfo);
if (rc == -EAGAIN) {
/* retry only once on 1st time connection */
atomic_set(&server->credits, 1);
+ server->current_smb2_mid = 0;
rc = SMB2_negotiate(xid, psesinfo);
if (rc == -EAGAIN)
rc = -EHOSTDOWN;
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 17/53] CIFS: Simplify SMB2 query info
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (6 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 14/53] CIFS: Expand cifs mid structure to keep SMB2 related fields Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 20/53] CIFS: Add SMB2 support for rmdir operation Pavel Shilovsky
` (19 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsproto.h | 13 +++-
fs/cifs/dir.c | 6 +-
fs/cifs/file.c | 5 +-
fs/cifs/inode.c | 165 +++++++++++++++++----------------------------------
fs/cifs/smb2dir.c | 71 ++++++++++++++++++++++
fs/cifs/smb2glob.h | 1 +
fs/cifs/smb2inode.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 13 ++--
8 files changed, 311 insertions(+), 128 deletions(-)
create mode 100644 fs/cifs/smb2dir.c
create mode 100644 fs/cifs/smb2inode.c
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5a2d6ef..607d3e4 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -141,14 +141,19 @@ 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 **pinode,
- const unsigned char *search_path,
- FILE_ALL_INFO *pfile_info,
- struct super_block *sb, int xid, const __u16 *pfid);
+extern int cifs_get_inode_info(struct inode **pinode, const char *full_path,
+ void *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, int xid);
+extern void cifs_all_info_to_fattr(struct cifs_fattr *fattr,
+ FILE_ALL_INFO *info,
+ struct cifs_sb_info *cifs_sb,
+ bool adjust_tz);
+extern void cifs_create_dfs_fattr(struct cifs_fattr *fattr,
+ struct super_block *sb);
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);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index d7eeb9d..3696f5b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -304,8 +304,8 @@ cifs_create_get_file_info:
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, &fileHandle);
if (newinode) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
@@ -594,7 +594,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
parent_dir_inode->i_sb, xid);
} else
rc = cifs_get_inode_info(&newInode, full_path, NULL,
- parent_dir_inode->i_sb, xid, NULL);
+ parent_dir_inode->i_sb, xid, NULL);
if ((rc == 0) && (newInode != NULL)) {
d_add(direntry, newInode);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ea096ce..1b9bae6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -568,9 +568,8 @@ reopen_success:
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);
+ 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
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 4d03038..cb5da45 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -32,6 +32,7 @@
#include "cifs_unicode.h"
#include "fscache.h"
#ifdef CONFIG_CIFS_SMB2
+#include "smb2glob.h"
#include "smb2proto.h"
#endif
@@ -271,7 +272,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
* junction to the new submount (ie to setup the fake directory
* which represents a DFS referral).
*/
-static void
+void
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -506,7 +507,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
}
/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
-static void
+void
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
struct cifs_sb_info *cifs_sb, bool adjust_tz)
{
@@ -598,73 +599,15 @@ cgfi_exit:
return rc;
}
-#ifdef CONFIG_CIFS_SMB2
-static void
-move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src)
-{
- memcpy(dst, src,
- (unsigned int)(&src->CurrentByteOffset) - (unsigned int)src);
- dst->CurrentByteOffset = src->CurrentByteOffset;
- dst->Mode = src->Mode;
- dst->AlignmentRequirement = src->AlignmentRequirement;
- dst->IndexNumber1 = 0; /* we don't use it */
-}
-
static int
-smb2_qinfo_helper(int xid, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
- const unsigned char *full_path, FILE_ALL_INFO *pfindData)
-{
- const unsigned char *start_full_path = full_path;
- __u64 persistent_fid, volatile_fid;
- FILE_ALL_INFO_SMB2 *data = NULL;
- __le16 *path = NULL;
- int usc_len, rc;
-
- data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2, GFP_KERNEL);
- if (data == NULL) {
- rc = -ENOMEM;
- goto out;
- }
-
- if (strlen(full_path) && full_path[0] == '\\')
- start_full_path += 1;
-
- path = smb2_strndup_to_ucs(start_full_path,
- PATH_MAX, &usc_len,
- cifs_sb->local_nls);
- if (path == NULL) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = SMB2_open(xid, tcon, path, &persistent_fid, &volatile_fid,
- FILE_READ_ATTRIBUTES_LE, FILE_OPEN_LE, 0, 0);
- if (!rc) {
- rc = SMB2_query_info(xid, tcon, persistent_fid,
- volatile_fid, data);
- SMB2_close(xid, tcon, persistent_fid,
- volatile_fid);
- }
-
- if (rc)
- goto out;
-
- move_smb2_info_to_cifs(pfindData, data);
-out:
- kfree(data);
- kfree(path);
- return rc;
-}
-#endif
-
-int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
- FILE_ALL_INFO *pfindData, struct super_block *sb,
- int xid, const __u16 *pfid)
+cifs_query_inode_info(struct inode **pinode, const char *full_path,
+ FILE_ALL_INFO *data, struct super_block *sb, int xid,
+ const __u16 *fid)
{
int rc = 0, tmprc;
- struct cifs_tcon *pTcon;
- struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct tcon_link *tlink;
char *buf = NULL;
bool adjustTZ = false;
struct cifs_fattr fattr;
@@ -672,66 +615,54 @@ int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
cFYI(1, "Getting info on %s", full_path);
- if ((pfindData == NULL) && (*pinode != NULL)) {
+ if ((data == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) {
cFYI(1, "No need to revalidate cached inode sizes");
- goto cgii_exit;
+ goto cqii_exit;
}
}
/* if file info not passed in then get it from server */
- if (pfindData == NULL) {
+ if (data == NULL) {
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) {
rc = -ENOMEM;
- goto cgii_exit;
+ goto cqii_exit;
}
- pfindData = (FILE_ALL_INFO *)buf;
-
- if (pTcon->ses->server->is_smb2 == false) {
- /*
- * Could do find first instead but this returns more
- * info.
- */
- rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
- 0 /* not legacy */,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- /*
- * BB optimize code so we do not make the above call
- * when server claims no NT SMB support and the above
- * call failed at least once - set flag in tcon or
- * mount.
- */
- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
- rc = SMBQueryInformation(xid, pTcon, full_path,
- pfindData, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- adjustTZ = true;
- }
-#ifdef CONFIG_CIFS_SMB2
- } else
- rc = smb2_qinfo_helper(xid, cifs_sb, pTcon, full_path,
- pfindData);
-#else
+ data = (FILE_ALL_INFO *)buf;
+
+ /* Could do find first instead but this returns more info */
+ rc = CIFSSMBQPathInfo(xid, tcon, full_path, data,
+ 0 /* not legacy */,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ /*
+ * BB optimize code so we do not make the above call when server
+ * claims no NT SMB support and the above call failed at least
+ * once - set flag in tcon or mount.
+ */
+ if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+ rc = SMBQueryInformation(xid, tcon, full_path,
+ data, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ adjustTZ = true;
}
-#endif
}
if (!rc) {
- cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
+ cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) data,
cifs_sb, adjustTZ);
} else if (rc == -EREMOTE) {
cifs_create_dfs_fattr(&fattr, sb);
rc = 0;
} else {
- goto cgii_exit;
+ goto cqii_exit;
}
/*
@@ -752,11 +683,10 @@ int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
* guaranteed unique?
*/
if (*pinode == NULL) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
- pTcon->ses->server->is_smb2 == false) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
int rc1 = 0;
- rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
+ rc1 = CIFSGetSrvInodeNumber(xid, tcon,
full_path, &fattr.cf_uniqueid,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -785,11 +715,11 @@ int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
- pfid);
+ fid);
if (rc) {
cFYI(1, "%s: Getting ACL failed with error: %d",
__func__, rc);
- goto cgii_exit;
+ goto cqii_exit;
}
}
#endif /* CONFIG_CIFS_ACL */
@@ -813,12 +743,25 @@ int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path,
cifs_fattr_to_inode(*pinode, &fattr);
}
-cgii_exit:
+cqii_exit:
kfree(buf);
cifs_put_tlink(tlink);
return rc;
}
+int
+cifs_get_inode_info(struct inode **pinode, const char *full_path, void *data,
+ struct super_block *sb, int xid, const __u16 *fid)
+{
+#ifdef CONFIG_CIFS_SMB2
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(CIFS_SB(sb));
+
+ if (tcon->ses->server->is_smb2)
+ return smb2_query_inode_info(pinode, full_path, data, sb, xid);
+#endif
+ return cifs_query_inode_info(pinode, full_path, data, sb, xid, fid);
+}
+
static const struct inode_operations cifs_ipc_inode_ops = {
.lookup = cifs_lookup,
};
@@ -1833,8 +1776,8 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
else
- rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
- xid, NULL);
+ rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid,
+ NULL);
out:
kfree(full_path);
diff --git a/fs/cifs/smb2dir.c b/fs/cifs/smb2dir.c
new file mode 100644
index 0000000..f297e2c
--- /dev/null
+++ b/fs/cifs/smb2dir.c
@@ -0,0 +1,71 @@
+/*
+ * fs/cifs/smb2dir.c
+ *
+ * Copyright (C) 2011
+ * Author(s): Pavel Shilovsky (piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org),
+ * Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
+ *
+ * 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 "smb2glob.h"
+#include "smb2proto.h"
+
+/* Note: caller must free return buffer */
+__le16 *
+cifs_convert_path_to_ucs(const char *from, struct nls_table *local_nls)
+{
+ int ucs_len;
+ const char *start_of_path;
+ __le16 *ucs_full_path;
+
+ /* Windows doesn't allow paths beginning with \ */
+ if (from[0] == '\\')
+ start_of_path = from + 1;
+ else
+ start_of_path = from;
+ ucs_full_path = smb2_strndup_to_ucs(start_of_path, PATH_MAX,
+ &ucs_len, local_nls);
+ return ucs_full_path;
+}
+
+__le16 *
+build_ucspath_from_dentry(struct dentry *direntry)
+{
+ char *full_path;
+ __le16 *ucs_path;
+
+ full_path = build_path_from_dentry(direntry);
+ if (full_path == NULL)
+ return NULL;
+
+ ucs_path = cifs_convert_path_to_ucs(full_path,
+ CIFS_SB(direntry->d_sb)->local_nls);
+ kfree(full_path);
+ return ucs_path;
+}
+
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 0e9fba7..1fe5813 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -182,6 +182,7 @@ struct page_req {
#define SMB2_OP_QUERY_DIR 4
#define SMB2_OP_MKDIR 5
#define SMB2_OP_RENAME 6
+#define SMB2_OP_DELETE 7
/* Used when constructing chained read requests. */
#define CHAINED_REQUEST 1
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
new file mode 100644
index 0000000..1d5e139
--- /dev/null
+++ b/fs/cifs/smb2inode.c
@@ -0,0 +1,165 @@
+/*
+ * fs/cifs/smb2inode.c
+ *
+ * Copyright (C) 2011
+ * Author(s): Pavel Shilovsky (piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org),
+ * Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
+ *
+ * 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 "smb2glob.h"
+#include "smb2proto.h"
+
+static int
+smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
+ __u32 desired_access, __u32 create_disposition,
+ __u32 file_attributes, __u32 create_options,
+ void *data, int command)
+{
+ int rc, tmprc = 0;
+ u64 persist_fid, volatile_fid;
+
+ rc = SMB2_open(xid, tcon, srch_path, &persist_fid, &volatile_fid,
+ desired_access, create_disposition, file_attributes,
+ create_options);
+ if (rc)
+ return rc;
+
+ switch (command) {
+ case SMB2_OP_DELETE:
+ break;
+ case SMB2_OP_QUERY_INFO:
+ tmprc = SMB2_query_info(xid, tcon, persist_fid,
+ volatile_fid,
+ (FILE_ALL_INFO_SMB2 *)data);
+ break;
+ case SMB2_OP_MKDIR:
+ /* Directories are created through parameters in the
+ * SMB2_open() call. */
+ break;
+ default:
+ cERROR(1, "Invalid command");
+ break;
+ }
+
+ rc = SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ if (tmprc)
+ rc = tmprc;
+
+ return rc;
+}
+
+static void
+move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src)
+{
+ memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
+ dst->CurrentByteOffset = src->CurrentByteOffset;
+ dst->Mode = src->Mode;
+ dst->AlignmentRequirement = src->AlignmentRequirement;
+ dst->IndexNumber1 = 0; /* we don't use it */
+}
+
+static int
+smb2_qinfo_helper(int xid, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ const char *full_path, FILE_ALL_INFO *data)
+{
+ int rc;
+ __le16 *smb2_path;
+ FILE_ALL_INFO_SMB2 *smb2_data;
+
+ smb2_data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2,
+ GFP_KERNEL);
+ if (smb2_data == NULL)
+ return -ENOMEM;
+
+ smb2_path = cifs_convert_path_to_ucs(full_path, cifs_sb->local_nls);
+ if (smb2_path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = smb2_open_op_close(xid, tcon, smb2_path, FILE_READ_ATTRIBUTES,
+ FILE_OPEN, 0, 0, smb2_data,
+ SMB2_OP_QUERY_INFO);
+ if (rc)
+ goto out;
+
+ move_smb2_info_to_cifs(data, smb2_data);
+out:
+ kfree(smb2_path);
+ kfree(smb2_data);
+ return rc;
+}
+
+int smb2_get_inode_info(struct inode **pinode, const char *full_path,
+ FILE_ALL_INFO *data, struct super_block *sb,
+ int xid, struct cifs_tcon *tcon)
+{
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ char *buf = NULL;
+ struct cifs_fattr fattr;
+
+ /* if file info not passed in then get it from server */
+ if (data == NULL) {
+ buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+ if (buf == NULL) {
+ rc = -ENOMEM;
+ goto sgii_exit;
+ }
+ data = (FILE_ALL_INFO *)buf;
+ rc = smb2_qinfo_helper(xid, cifs_sb, tcon, full_path, data);
+ }
+
+ if (!rc) {
+ cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) data,
+ cifs_sb, false);
+ } else if (rc == -EREMOTE) {
+ cifs_create_dfs_fattr(&fattr, sb);
+ rc = 0;
+ } else {
+ goto sgii_exit;
+ }
+
+ if (*pinode == NULL)
+ fattr.cf_uniqueid = iunique(sb, ROOT_I);
+ else
+ fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
+
+ if (!*pinode) {
+ *pinode = cifs_iget(sb, &fattr);
+ if (!*pinode)
+ rc = -ENOMEM;
+ } else {
+ cifs_fattr_to_inode(*pinode, &fattr);
+ }
+
+sgii_exit:
+ kfree(buf);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e826279..9744dc0 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -47,6 +47,9 @@ extern int checkSMB2(struct smb2_hdr *smb2, __u64 mid, unsigned int length);
extern char *smb2_get_data_area_len(int *poff, int *pln, struct smb2_hdr *psmb);
extern unsigned int smb2_calc_size(struct smb2_hdr *ptr);
extern int map_smb2_to_linux_error(struct smb2_hdr *smb2, int logErr);
+extern __le16 *cifs_build_ucspath_from_dentry(struct dentry *);
+extern __le16 *cifs_convert_path_to_ucs(const char *from,
+ struct nls_table *local_nls);
extern int smb2_send(struct TCP_Server_Info *, struct smb2_hdr *,
unsigned int /* length */);
@@ -76,13 +79,9 @@ extern int smb2_setup_session(unsigned int xid, struct cifs_ses *pses_info,
struct nls_table *nls_info);
extern int smb2_umount(struct super_block *, struct cifs_sb_info *);
-extern int smb2_get_inode_info(struct inode **pinode, __le16 *search_path,
- FILE_ALL_INFO *pfile_info, struct super_block *sb,
- int xid);
-extern struct smb2_file *smb2_new_fileinfo(struct inode *newinode,
- u64 persistfid, u64 volatile_fid,
- struct file *file, struct vfsmount *mnt,
- unsigned int oflags);
+extern int smb2_query_inode_info(struct inode **pinode, const char *full_path,
+ FILE_ALL_INFO *data, struct super_block *sb,
+ int xid);
extern bool smb2_is_size_safe_to_change(struct smb2_inode *smb2_ind,
__u64 end_of_file);
extern struct inode *smb2_iget(struct super_block *sb,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 18/53] CIFS: Add SMB2 inode/dentry ops structures
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (6 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 16/53] CIFS: Get mount/umount work with SMB2 protocol Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 19/53] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
` (15 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsfs.c | 2 +-
fs/cifs/cifsfs.h | 2 +-
fs/cifs/inode.c | 21 +++++++++-
fs/cifs/smb2dir.c | 8 ++++
fs/cifs/smb2inode.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 11 ++++-
6 files changed, 140 insertions(+), 7 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index fce81fc..d402c89 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -215,7 +215,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static int cifs_permission(struct inode *inode, int mask)
+int cifs_permission(struct inode *inode, int mask)
{
struct cifs_sb_info *cifs_sb;
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 30ff560..2009adc 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -62,12 +62,12 @@ extern int cifs_revalidate_dentry(struct dentry *);
extern int cifs_invalidate_mapping(struct inode *inode);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *);
+extern int cifs_permission(struct inode *inode, int mask);
extern const struct inode_operations cifs_file_inode_ops;
extern const struct inode_operations cifs_symlink_inode_ops;
extern const struct inode_operations cifs_dfs_referral_inode_operations;
-
/* Functions related to files and directories */
extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cb5da45..ba175ad 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -87,8 +87,23 @@ static void cifs_set_ops(struct inode *inode)
}
}
-/* check inode attributes against fattr. If they don't match, tag the
- * inode for cache invalidation
+static void cifs_set_ops_generic(struct inode *inode)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_tcon *tcon;
+
+ tcon = cifs_sb_master_tcon(cifs_sb);
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2)
+ smb2_set_ops(inode);
+ else
+#endif
+ cifs_set_ops(inode);
+}
+
+/*
+ * Check inode attributes against fattr. If they don't match, tag the
+ * inode for cache invalidation.
*/
static void
cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
@@ -177,7 +192,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
inode->i_flags |= S_AUTOMOUNT;
- cifs_set_ops(inode);
+ cifs_set_ops_generic(inode);
}
void
diff --git a/fs/cifs/smb2dir.c b/fs/cifs/smb2dir.c
index f297e2c..957338c 100644
--- a/fs/cifs/smb2dir.c
+++ b/fs/cifs/smb2dir.c
@@ -35,6 +35,14 @@
#include "smb2glob.h"
#include "smb2proto.h"
+const struct file_operations smb2_dir_ops = {
+ .readdir = cifs_readdir,
+ .release = cifs_closedir,
+ .read = generic_read_dir,
+ .unlocked_ioctl = cifs_ioctl,
+ .llseek = generic_file_llseek,
+};
+
/* Note: caller must free return buffer */
__le16 *
cifs_convert_path_to_ucs(const char *from, struct nls_table *local_nls)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1d5e139..1ec35f6 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -35,6 +35,109 @@
#include "smb2glob.h"
#include "smb2proto.h"
+const struct inode_operations smb2_dir_inode_ops = {
+ .create = cifs_create,
+ .lookup = cifs_lookup,
+ .getattr = cifs_getattr,
+ .unlink = cifs_unlink,
+ .link = cifs_hardlink,
+ .mkdir = cifs_mkdir,
+ .rmdir = cifs_rmdir,
+ .rename = cifs_rename,
+ .permission = cifs_permission,
+/* revalidate:cifs_revalidate, */
+ .setattr = cifs_setattr,
+ .symlink = cifs_symlink,
+ .mknod = cifs_mknod,
+#ifdef CONFIG_CIFS_XATTR
+ .setxattr = cifs_setxattr,
+ .getxattr = cifs_getxattr,
+ .listxattr = cifs_listxattr,
+ .removexattr = cifs_removexattr,
+#endif
+};
+
+const struct inode_operations smb2_file_inode_ops = {
+/* revalidate:cifs_revalidate, */
+ .setattr = cifs_setattr,
+ .getattr = cifs_getattr, /* do we need this anymore? */
+ .rename = cifs_rename,
+ .permission = cifs_permission,
+#ifdef CONFIG_CIFS_XATTR
+ .setxattr = cifs_setxattr,
+ .getxattr = cifs_getxattr,
+ .listxattr = cifs_listxattr,
+ .removexattr = cifs_removexattr,
+#endif
+};
+
+const struct inode_operations smb2_symlink_inode_ops = {
+ .readlink = generic_readlink,
+ .follow_link = cifs_follow_link,
+ .put_link = cifs_put_link,
+ .permission = cifs_permission,
+ /* BB add the following two eventually */
+ /* revalidate: cifs_revalidate,
+ setattr: cifs_notify_change, *//* BB do we need notify change */
+#ifdef CONFIG_CIFS_XATTR
+ .setxattr = cifs_setxattr,
+ .getxattr = cifs_getxattr,
+ .listxattr = cifs_listxattr,
+ .removexattr = cifs_removexattr,
+#endif
+};
+
+void smb2_set_ops(struct inode *inode)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_op = &smb2_file_inode_ops;
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ inode->i_fop = &cifs_file_direct_nobrl_ops;
+ else
+ inode->i_fop = &cifs_file_direct_ops;
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ inode->i_fop = &cifs_file_strict_nobrl_ops;
+ else
+ inode->i_fop = &cifs_file_strict_ops;
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ inode->i_fop = &cifs_file_nobrl_ops;
+ else { /* not direct, send byte range locks */
+ inode->i_fop = &cifs_file_ops;
+ }
+
+ /* check if server can support readpages */
+ if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
+ PAGE_CACHE_SIZE)
+ inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+ else
+ inode->i_data.a_ops = &cifs_addr_ops;
+ break;
+ case S_IFDIR:
+#ifdef CONFIG_CIFS_DFS_UPCALL
+ if (IS_AUTOMOUNT(inode)) {
+ inode->i_op = &cifs_dfs_referral_inode_operations;
+ } else {
+#else /* NO DFS support, treat as a directory */
+ {
+#endif
+ inode->i_op = &smb2_dir_inode_ops;
+ inode->i_fop = &smb2_dir_ops;
+ }
+ break;
+ case S_IFLNK:
+ inode->i_op = &smb2_symlink_inode_ops;
+ break;
+ default:
+ init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ break;
+ }
+}
+
static int
smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
__u32 desired_access, __u32 create_disposition,
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 9744dc0..9fc2e74 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -31,9 +31,15 @@ struct statfs;
*****************************************************************
*/
-/* extern char *build_smb2path_from_dentry(struct dentry *);
+extern const struct inode_operations smb2_file_inode_ops;
+extern const struct inode_operations smb2_dir_inode_ops;
+extern const struct inode_operations smb2_symlink_inode_ops;
+
+extern const struct file_operations smb2_dir_ops;
+
+/* extern char *build_smb2path_from_dentry(struct dentry *);*/
extern __le16 *build_ucspath_from_dentry(struct dentry *);
-extern __le16 *smb2_build_path_to_root(struct cifs_sb_info *smb2_sb);
+/*extern __le16 *smb2_build_path_to_root(struct cifs_sb_info *smb2_sb);
extern void free_rsp_buf(int resp_buftype, void *pSMB2r);
extern struct smb2_hdr *smb2_buf_get(void);
extern void smb2_buf_release(void *);
@@ -82,6 +88,7 @@ extern int smb2_umount(struct super_block *, struct cifs_sb_info *);
extern int smb2_query_inode_info(struct inode **pinode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid);
+extern void smb2_set_ops(struct inode *inode);
extern bool smb2_is_size_safe_to_change(struct smb2_inode *smb2_ind,
__u64 end_of_file);
extern struct inode *smb2_iget(struct super_block *sb,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 19/53] CIFS: Add SMB2 support for mkdir operation
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (7 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 18/53] CIFS: Add SMB2 inode/dentry ops structures Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 22/53] CIFS: Add SMB2 support for open/close file operations Pavel Shilovsky
` (14 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsfs.c | 3 +
fs/cifs/smb2inode.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++---
fs/cifs/smb2proto.h | 3 +-
3 files changed, 126 insertions(+), 8 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d402c89..c7b316e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -49,6 +49,9 @@
#include "cifs_spnego.h"
#include "fscache.h"
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
int cifsFYI = 0;
int cifsERROR = 1;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1ec35f6..09df087 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -41,7 +41,7 @@ const struct inode_operations smb2_dir_inode_ops = {
.getattr = cifs_getattr,
.unlink = cifs_unlink,
.link = cifs_hardlink,
- .mkdir = cifs_mkdir,
+ .mkdir = smb2_mkdir,
.rmdir = cifs_rmdir,
.rename = cifs_rename,
.permission = cifs_permission,
@@ -219,21 +219,37 @@ out:
return rc;
}
-int smb2_get_inode_info(struct inode **pinode, const char *full_path,
- FILE_ALL_INFO *data, struct super_block *sb,
- int xid, struct cifs_tcon *tcon)
+int
+smb2_query_inode_info(struct inode **pinode, const char *full_path,
+ FILE_ALL_INFO *data, struct super_block *sb, int xid)
{
int rc = 0;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *buf = NULL;
struct cifs_fattr fattr;
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ cFYI(1, "Getting info on %s", full_path);
+
+ if ((data == NULL) && (*pinode != NULL)) {
+ if (CIFS_I(*pinode)->clientCanCacheRead) {
+ cFYI(1, "No need to revalidate cached inode sizes");
+ goto sqii_exit;
+ }
+ }
+
/* if file info not passed in then get it from server */
if (data == NULL) {
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) {
rc = -ENOMEM;
- goto sgii_exit;
+ goto sqii_exit;
}
data = (FILE_ALL_INFO *)buf;
rc = smb2_qinfo_helper(xid, cifs_sb, tcon, full_path, data);
@@ -246,7 +262,7 @@ int smb2_get_inode_info(struct inode **pinode, const char *full_path,
cifs_create_dfs_fattr(&fattr, sb);
rc = 0;
} else {
- goto sgii_exit;
+ goto sqii_exit;
}
if (*pinode == NULL)
@@ -262,7 +278,105 @@ int smb2_get_inode_info(struct inode **pinode, const char *full_path,
cifs_fattr_to_inode(*pinode, &fattr);
}
-sgii_exit:
+sqii_exit:
kfree(buf);
+ cifs_put_tlink(tlink);
+ return rc;
+}
+
+int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode)
+{
+ int rc = 0, tmprc;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct inode *newinode = NULL;
+ __le16 *ucs_path = NULL;
+ char *full_path = NULL;
+
+ cFYI(1, "In mkdir, mode = 0x%x inode = 0x%p", mode, inode);
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ xid = GetXid();
+
+ full_path = build_path_from_dentry(direntry);
+ if (full_path == NULL) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ ucs_path = cifs_convert_path_to_ucs(full_path, cifs_sb->local_nls);
+ if (ucs_path == NULL) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ rc = smb2_open_op_close(xid, tcon, ucs_path, FILE_WRITE_ATTRIBUTES,
+ FILE_CREATE, 0, CREATE_NOT_FILE, NULL,
+ SMB2_OP_MKDIR);
+ if (rc)
+ goto err_out;
+
+ inc_nlink(inode);
+
+ 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))
+ direntry->d_inode->i_nlink = 2;
+
+ mode &= ~current_umask();
+ /* must turn on setgid bit if parent dir has it */
+ if (inode->i_mode & S_ISGID)
+ mode |= S_ISGID;
+
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ (mode & S_IWUGO) == 0) {
+ FILE_BASIC_INFO data;
+ struct cifsInodeInfo *cifs_i;
+ u32 dosattrs;
+ memset(&data, 0, sizeof(data));
+ cifs_i = CIFS_I(newinode);
+ dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
+ data.Attributes = cpu_to_le32(dosattrs);
+ tmprc = smb2_open_op_close(xid, tcon, ucs_path,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_CREATE, 0,
+ CREATE_NOT_FILE, &data,
+ SMB2_OP_SET_INFO);
+ if (tmprc == 0)
+ cifs_i->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();
+ }
+ }
+
+out:
+ kfree(ucs_path);
+ FreeXid(xid);
+ cifs_put_tlink(tlink);
return rc;
+err_out:
+ cFYI(1, "smb2_mkdir returned 0x%x", rc);
+ d_drop(direntry);
+ goto out;
}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 9fc2e74..c73e664 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -53,7 +53,6 @@ extern int checkSMB2(struct smb2_hdr *smb2, __u64 mid, unsigned int length);
extern char *smb2_get_data_area_len(int *poff, int *pln, struct smb2_hdr *psmb);
extern unsigned int smb2_calc_size(struct smb2_hdr *ptr);
extern int map_smb2_to_linux_error(struct smb2_hdr *smb2, int logErr);
-extern __le16 *cifs_build_ucspath_from_dentry(struct dentry *);
extern __le16 *cifs_convert_path_to_ucs(const char *from,
struct nls_table *local_nls);
@@ -102,6 +101,8 @@ extern void cifs_fattr_to_inode(struct inode *pinode, struct cifs_fattr *attr);
extern int smb2_fsync(struct file *file, int datasync);
extern int smb2_flush(struct file *file, fl_owner_t id);
+extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
+
/* extern char *smb2_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 20/53] CIFS: Add SMB2 support for rmdir operation
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (7 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 17/53] CIFS: Simplify SMB2 query info Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 21/53] CIFS: Add SMB2 support for unlink operation Pavel Shilovsky
` (18 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2proto.h | 1 +
2 files changed, 60 insertions(+), 1 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 09df087..5947e49 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -42,7 +42,7 @@ const struct inode_operations smb2_dir_inode_ops = {
.unlink = cifs_unlink,
.link = cifs_hardlink,
.mkdir = smb2_mkdir,
- .rmdir = cifs_rmdir,
+ .rmdir = smb2_rmdir,
.rename = cifs_rename,
.permission = cifs_permission,
/* revalidate:cifs_revalidate, */
@@ -380,3 +380,61 @@ err_out:
d_drop(direntry);
goto out;
}
+
+int smb2_rmdir(struct inode *inode, struct dentry *direntry)
+{
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ __le16 *ucs_path = NULL;
+ struct cifsInodeInfo *cifsInode;
+
+ cFYI(1, "smb2_rmdir, inode = 0x%p", inode);
+
+ xid = GetXid();
+
+ ucs_path = build_ucspath_from_dentry(direntry);
+ if (ucs_path == NULL) {
+ rc = -ENOMEM;
+ goto rmdir_exit;
+ }
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink)) {
+ rc = PTR_ERR(tlink);
+ goto rmdir_exit;
+ }
+ tcon = tlink_tcon(tlink);
+
+ rc = smb2_open_op_close(xid, tcon, ucs_path, DELETE,
+ FILE_OPEN, 0, CREATE_NOT_FILE |
+ CREATE_DELETE_ON_CLOSE, NULL, SMB2_OP_DELETE);
+ cifs_put_tlink(tlink);
+
+ if (!rc) {
+ drop_nlink(inode);
+ spin_lock(&direntry->d_inode->i_lock);
+ i_size_write(direntry->d_inode, 0);
+ clear_nlink(direntry->d_inode);
+ spin_unlock(&direntry->d_inode->i_lock);
+ }
+
+ cifsInode = CIFS_I(direntry->d_inode);
+ cifsInode->time = 0; /* force revalidate to go get info when
+ needed */
+
+ cifsInode = CIFS_I(inode);
+ cifsInode->time = 0; /* force revalidate to get parent dir info
+ since cached search results now invalid */
+
+ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
+ current_fs_time(inode->i_sb);
+
+rmdir_exit:
+ kfree(ucs_path);
+ FreeXid(xid);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index c73e664..b1a7801 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -102,6 +102,7 @@ extern int smb2_fsync(struct file *file, int datasync);
extern int smb2_flush(struct file *file, fl_owner_t id);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
+extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
/* extern char *smb2_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 21/53] CIFS: Add SMB2 support for unlink operation
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (8 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 20/53] CIFS: Add SMB2 support for rmdir operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 24/53] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
` (17 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2proto.h | 1 +
2 files changed, 90 insertions(+), 1 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 5947e49..9111153 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -39,7 +39,7 @@ const struct inode_operations smb2_dir_inode_ops = {
.create = cifs_create,
.lookup = cifs_lookup,
.getattr = cifs_getattr,
- .unlink = cifs_unlink,
+ .unlink = smb2_unlink,
.link = cifs_hardlink,
.mkdir = smb2_mkdir,
.rmdir = smb2_rmdir,
@@ -438,3 +438,91 @@ rmdir_exit:
FreeXid(xid);
return rc;
}
+
+int smb2_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int rc = 0;
+ int xid;
+ struct inode *inode = dentry->d_inode;
+ struct cifsInodeInfo *cifs_inode;
+ struct super_block *sb = dir->i_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct iattr *attrs = NULL;
+ __le16 *ucs_path = NULL;
+ __u32 dosattr = 0, origattr = 0;
+
+ cFYI(1, "smb2_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ xid = GetXid();
+
+ /* Unlink can be called from rename so we can not take the
+ * sb->s_vfs_rename_mutex here */
+ ucs_path = build_ucspath_from_dentry(dentry);
+ if (ucs_path == NULL) {
+ rc = -ENOMEM;
+ goto unlink_out;
+ }
+
+ rc = smb2_open_op_close(xid, tcon, ucs_path, DELETE,
+ FILE_OPEN, 0, CREATE_DELETE_ON_CLOSE, NULL,
+ SMB2_OP_DELETE);
+ if (!rc) {
+ if (inode)
+ 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);*/
+ } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
+ attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
+ if (attrs == NULL) {
+ rc = -ENOMEM;
+ goto out_reval;
+ }
+
+ /* try to reset dos attributes */
+ cifs_inode = CIFS_I(inode);
+ origattr = cifs_inode->cifsAttrs;
+ if (origattr == 0)
+ origattr |= ATTR_NORMAL;
+ dosattr = origattr & ~ATTR_READONLY;
+ if (dosattr == 0)
+ dosattr |= ATTR_NORMAL;
+ dosattr |= ATTR_HIDDEN;
+
+/* rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
+ if (rc != 0)
+ goto out_reval;
+
+ goto retry_std_delete;*/
+ }
+
+ /* undo the setattr if we errored out and it's needed */
+/* if (rc != 0 && dosattr != 0)
+ cifs_set_file_info(inode, attrs, xid, full_path, origattr);*/
+out_reval:
+ if (inode) {
+ cifs_inode = CIFS_I(inode);
+ cifs_inode->time = 0; /* will force revalidate to get info
+ when needed */
+ inode->i_ctime = current_fs_time(sb);
+ }
+ dir->i_ctime = dir->i_mtime = current_fs_time(sb);
+ cifs_inode = CIFS_I(dir);
+ CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
+unlink_out:
+ kfree(attrs);
+ kfree(ucs_path);
+ FreeXid(xid);
+ cifs_put_tlink(tlink);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index b1a7801..2c5cf2c 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -103,6 +103,7 @@ extern int smb2_flush(struct file *file, fl_owner_t id);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
+extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
/* extern char *smb2_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 22/53] CIFS: Add SMB2 support for open/close file operations
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (8 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 19/53] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 23/53] CIFS: Add SMB2 support for reopen file operation Pavel Shilovsky
` (13 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsfs.c | 85 ----------------
fs/cifs/cifsfs.h | 4 +
fs/cifs/cifsglob.h | 4 +
fs/cifs/cifsproto.h | 19 +++--
fs/cifs/file.c | 141 +++++++++++++++++++++++---
fs/cifs/smb2file.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2inode.c | 14 ++--
fs/cifs/smb2pdu.c | 4 +-
fs/cifs/smb2proto.h | 15 +++
9 files changed, 442 insertions(+), 118 deletions(-)
create mode 100644 fs/cifs/smb2file.c
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c7b316e..7991a53 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -686,91 +686,6 @@ out_nls:
goto out;
}
-static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
- ssize_t written;
- int rc;
-
- written = generic_file_aio_write(iocb, iov, nr_segs, pos);
-
- if (CIFS_I(inode)->clientCanCacheAll)
- return written;
-
- rc = filemap_fdatawrite(inode->i_mapping);
- if (rc)
- cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode);
-
- return written;
-}
-
-static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
-{
- /*
- * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
- * the cached file length
- */
- if (origin != SEEK_SET || origin != SEEK_CUR) {
- int rc;
- struct inode *inode = file->f_path.dentry->d_inode;
-
- /*
- * We need to be sure that all dirty pages are written and the
- * server has the newest file length.
- */
- if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
- inode->i_mapping->nrpages != 0) {
- rc = filemap_fdatawait(inode->i_mapping);
- if (rc) {
- mapping_set_error(inode->i_mapping, rc);
- return rc;
- }
- }
- /*
- * Some applications poll for the file length in this strange
- * way so we must seek to end on non-oplocked files by
- * setting the revalidate time to zero.
- */
- CIFS_I(inode)->time = 0;
-
- rc = cifs_revalidate_file_attr(file);
- if (rc < 0)
- return (loff_t)rc;
- }
- return generic_file_llseek_unlocked(file, offset, origin);
-}
-
-static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
-{
- /* note that this is called by vfs setlease with lock_flocks held
- to protect *lease from going away */
- struct inode *inode = file->f_path.dentry->d_inode;
- struct cifsFileInfo *cfile = file->private_data;
-
- if (!(S_ISREG(inode->i_mode)))
- return -EINVAL;
-
- /* check if file is oplocked */
- if (((arg == F_RDLCK) &&
- (CIFS_I(inode)->clientCanCacheRead)) ||
- ((arg == F_WRLCK) &&
- (CIFS_I(inode)->clientCanCacheAll)))
- return generic_setlease(file, arg, lease);
- else if (tlink_tcon(cfile->tlink)->local_lease &&
- !CIFS_I(inode)->clientCanCacheRead)
- /* If the server claims to support oplock on this
- file, then we still need to check oplock even
- if the local_lease mount option is set, but there
- are servers which do not support oplock for which
- this mount option may be useful if the user
- knows that the file won't be changed on the server
- by anyone else */
- return generic_setlease(file, arg, lease);
- else
- return -EAGAIN;
-}
-
struct file_system_type cifs_fs_type = {
.owner = THIS_MODULE,
.name = "cifs",
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 2009adc..198a141 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -82,6 +82,8 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
+extern ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
@@ -92,6 +94,8 @@ extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
extern int cifs_flush(struct file *, fl_owner_t id);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
+extern int cifs_setlease(struct file *file, long arg, struct file_lock **lease);
+extern loff_t cifs_llseek(struct file *file, loff_t offset, int origin);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a2b14d8..e6ea8de 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -579,6 +579,10 @@ struct cifsFileInfo {
unsigned int uid; /* allows finding which FileInfo structure */
__u32 pid; /* process id who opened file */
__u16 netfid; /* file id from remote */
+#ifdef CONFIG_CIFS_SMB2
+ __u64 volatile_fid; /* volatile file id for smb2 */
+ __u64 persist_fid; /* persist file id for smb2 */
+#endif
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct dentry *dentry;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 607d3e4..142660f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -125,13 +125,18 @@ 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 int cifs_posix_open(char *full_path, struct inode **pinode,
- struct super_block *sb,
- int mode, unsigned int f_flags,
- __u32 *poplock, __u16 *pnetfid, int xid);
+extern int cifs_convert_flags(unsigned int flags);
+extern int cifs_get_disposition(unsigned int flags);
+extern struct cifsFileInfo *cifs_new_fileinfo(__u16 netfid, struct file *file,
+ struct tcon_link *tlink,
+ __u32 oplock);
+extern struct cifsFileInfo *cifs_new_fileinfo_generic(struct file *file,
+ struct tcon_link *tlink,
+ __u32 oplock);
+extern int cifs_posix_open(const char *full_path, struct inode **pinode,
+ struct super_block *sb, int mode,
+ unsigned int f_flags, __u32 *poplock, __u16 *pnetfid,
+ int xid);
void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
FILE_UNIX_BASIC_INFO *info,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1b9bae6..37c8445 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -42,8 +42,11 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "fscache.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
-static inline int cifs_convert_flags(unsigned int flags)
+inline int cifs_convert_flags(unsigned int flags)
{
if ((flags & O_ACCMODE) == O_RDONLY)
return GENERIC_READ;
@@ -91,7 +94,7 @@ static u32 cifs_posix_convert_flags(unsigned int flags)
return posix_flags;
}
-static inline int cifs_get_disposition(unsigned int flags)
+inline int cifs_get_disposition(unsigned int flags)
{
if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
return FILE_CREATE;
@@ -105,9 +108,9 @@ static inline int cifs_get_disposition(unsigned int flags)
return FILE_OPEN;
}
-int cifs_posix_open(char *full_path, struct inode **pinode,
- struct super_block *sb, int mode, unsigned int f_flags,
- __u32 *poplock, __u16 *pnetfid, int xid)
+int cifs_posix_open(const char *full_path, struct inode **pinode,
+ struct super_block *sb, int mode, unsigned int f_flags,
+ __u32 *poplock, __u16 *pnetfid, int xid)
{
int rc;
FILE_UNIX_BASIC_INFO *presp_data;
@@ -168,9 +171,9 @@ 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, int xid)
+cifs_nt_open(const char *full_path, struct inode *inode,
+ struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ unsigned int f_flags, __u32 *poplock, __u16 *pnetfid, int xid)
{
int rc;
int desiredAccess;
@@ -242,9 +245,22 @@ out:
}
struct cifsFileInfo *
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+cifs_new_fileinfo(__u16 netfid, struct file *file,
struct tcon_link *tlink, __u32 oplock)
{
+ struct cifsFileInfo *cifs_file;
+
+ cifs_file = cifs_new_fileinfo_generic(file, tlink, oplock);
+ if (cifs_file == NULL)
+ return NULL;
+ cifs_file->netfid = netfid;
+ return cifs_file;
+}
+
+struct cifsFileInfo *
+cifs_new_fileinfo_generic(struct file *file, struct tcon_link *tlink,
+ __u32 oplock)
+{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
@@ -255,7 +271,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
return pCifsFile;
pCifsFile->count = 1;
- pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid;
pCifsFile->uid = current_fsuid();
pCifsFile->dentry = dget(dentry);
@@ -323,10 +338,16 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
cancel_work_sync(&cifs_file->oplock_break);
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
- int xid, rc;
+ int xid, rc = 0;
xid = GetXid();
- rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2)
+ rc = SMB2_close(xid, tcon, cifs_file->persist_fid,
+ cifs_file->volatile_fid);
+ else
+#endif
+ rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
FreeXid(xid);
}
@@ -348,7 +369,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
kfree(cifs_file);
}
-int cifs_open(struct inode *inode, struct file *file)
+int
+cifs_open(struct inode *inode, struct file *file)
{
int rc = -EACCES;
int xid;
@@ -356,7 +378,7 @@ 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 *cifs_file = NULL;
char *full_path = NULL;
bool posix_open_ok = false;
__u16 netfid;
@@ -419,8 +441,8 @@ int cifs_open(struct inode *inode, struct file *file)
goto out;
}
- pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
- if (pCifsFile == NULL) {
+ cifs_file = cifs_new_fileinfo(netfid, file, tlink, oplock);
+ if (cifs_file == NULL) {
CIFSSMBClose(xid, tcon, netfid);
rc = -ENOMEM;
goto out;
@@ -441,7 +463,7 @@ int cifs_open(struct inode *inode, struct file *file)
.device = 0,
};
CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
- pCifsFile->pid);
+ cifs_file->pid);
}
out:
@@ -643,6 +665,72 @@ int cifs_closedir(struct inode *inode, struct file *file)
return rc;
}
+loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
+{
+ /*
+ * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
+ * the cached file length
+ */
+ if (origin != SEEK_SET || origin != SEEK_CUR) {
+ int rc;
+ struct inode *inode = file->f_path.dentry->d_inode;
+
+ /*
+ * We need to be sure that all dirty pages are written and the
+ * server has the newest file length.
+ */
+ if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
+ inode->i_mapping->nrpages != 0) {
+ rc = filemap_fdatawait(inode->i_mapping);
+ if (rc) {
+ mapping_set_error(inode->i_mapping, rc);
+ return rc;
+ }
+ }
+ /*
+ * Some applications poll for the file length in this strange
+ * way so we must seek to end on non-oplocked files by
+ * setting the revalidate time to zero.
+ */
+ CIFS_I(inode)->time = 0;
+
+ rc = cifs_revalidate_file_attr(file);
+ if (rc < 0)
+ return (loff_t)rc;
+ }
+ return generic_file_llseek_unlocked(file, offset, origin);
+}
+
+int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
+{
+ /* note that this is called by vfs setlease with lock_flocks held
+ to protect *lease from going away */
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct cifsFileInfo *cfile = file->private_data;
+
+ if (!(S_ISREG(inode->i_mode)))
+ return -EINVAL;
+
+ /* check if file is oplocked */
+ if (((arg == F_RDLCK) &&
+ (CIFS_I(inode)->clientCanCacheRead)) ||
+ ((arg == F_WRLCK) &&
+ (CIFS_I(inode)->clientCanCacheAll)))
+ return generic_setlease(file, arg, lease);
+ else if (tlink_tcon(cfile->tlink)->local_lease &&
+ !CIFS_I(inode)->clientCanCacheRead)
+ /* If the server claims to support oplock on this
+ file, then we still need to check oplock even
+ if the local_lease mount option is set, but there
+ are servers which do not support oplock for which
+ this mount option may be useful if the user
+ knows that the file won't be changed on the server
+ by anyone else */
+ return generic_setlease(file, arg, lease);
+ else
+ return -EAGAIN;
+}
+
static struct cifsLockInfo *
cifs_lock_init(__u64 len, __u64 offset, __u8 type, __u16 netfid)
{
@@ -2178,6 +2266,25 @@ ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
return cifs_user_writev(iocb, iov, nr_segs, pos);
}
+ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+ ssize_t written;
+ int rc;
+
+ written = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+ if (CIFS_I(inode)->clientCanCacheAll)
+ return written;
+
+ rc = filemap_fdatawrite(inode->i_mapping);
+ if (rc)
+ cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode);
+
+ return written;
+}
+
static ssize_t
cifs_iovec_read(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *poffset)
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644
index 0000000..8b4d802
--- /dev/null
+++ b/fs/cifs/smb2file.c
@@ -0,0 +1,274 @@
+/*
+ * fs/cifs/smb2file.c
+ *
+ * Copyright (C) 2011
+ * Author(s): Pavel Shilovsky (piastryyy@gmail.com),
+ * Steve French (sfrench@us.ibm.com)
+ *
+ * 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 "smb2glob.h"
+#include "smb2proto.h"
+
+const struct file_operations smb2_file_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = cifs_file_aio_write,
+ .open = smb2_open,
+ .release = cifs_close,
+ .lock = cifs_lock,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
+const struct file_operations smb2_file_strict_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_strict_readv,
+ .aio_write = cifs_strict_writev,
+ .open = smb2_open,
+ .release = cifs_close,
+ .lock = cifs_lock,
+ .fsync = cifs_strict_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_strict_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
+const struct file_operations smb2_file_direct_ops = {
+ /* BB reevaluate whether they can be done with directio, no cache */
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_user_readv,
+ .aio_write = cifs_user_writev,
+ .open = smb2_open,
+ .release = cifs_close,
+ .lock = cifs_lock,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+ .splice_read = generic_file_splice_read,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .llseek = cifs_llseek,
+ .setlease = cifs_setlease,
+};
+
+const struct file_operations smb2_file_nobrl_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = cifs_file_aio_write,
+ .open = smb2_open,
+ .release = cifs_close,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
+const struct file_operations smb2_file_strict_nobrl_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_strict_readv,
+ .aio_write = cifs_strict_writev,
+ .open = smb2_open,
+ .release = cifs_close,
+ .fsync = cifs_strict_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_strict_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
+const struct file_operations smb2_file_direct_nobrl_ops = {
+ /* BB reevaluate whether they can be done with directio, no cache */
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_user_readv,
+ .aio_write = cifs_user_writev,
+ .open = smb2_open,
+ .release = cifs_close,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+ .splice_read = generic_file_splice_read,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .llseek = cifs_llseek,
+ .setlease = cifs_setlease,
+};
+
+struct cifsFileInfo *
+smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
+ struct tcon_link *tlink, __u32 oplock)
+{
+ struct cifsFileInfo *cifs_file;
+
+ cifs_file = cifs_new_fileinfo_generic(file, tlink, oplock);
+ if (cifs_file == NULL)
+ return NULL;
+ cifs_file->persist_fid = persist_fid;
+ cifs_file->volatile_fid = volatile_fid;
+ return cifs_file;
+}
+
+static int
+smb2_open_helper(struct file *file, struct inode *inode, const char *full_path,
+ __u8 *oplock, __u64 *persist_fid, __u64 *volatile_fid,
+ FILE_ALL_INFO *data, struct cifs_tcon *tcon, int xid)
+{
+ int rc;
+ __u32 desired_access = FILE_READ_ATTRIBUTES;
+ __u32 create_disposition;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ __le16 *smb2_path;
+ FILE_ALL_INFO_SMB2 *smb2_data = NULL;
+
+ desired_access = cifs_convert_flags(file->f_flags);
+ create_disposition = cifs_get_disposition(file->f_flags);
+
+ smb2_path = cifs_convert_path_to_ucs(full_path, cifs_sb->local_nls);
+ if (smb2_path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ smb2_data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2,
+ GFP_KERNEL);
+ if (smb2_data == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
+ desired_access, create_disposition, 0, 0);
+
+ if (rc)
+ goto out;
+
+ rc = SMB2_query_info(xid, tcon, *persist_fid, *volatile_fid, smb2_data);
+ if (rc) {
+ SMB2_close(xid, tcon, *persist_fid, *volatile_fid);
+ goto out;
+ }
+
+ move_smb2_info_to_cifs(data, smb2_data);
+out:
+ *oplock = 0;
+ kfree(smb2_data);
+ kfree(smb2_path);
+ return rc;
+}
+
+int smb2_open(struct inode *inode, struct file *file)
+{
+ int rc = -EACCES;
+ int xid;
+ __u8 oplock;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsFileInfo *cifs_file;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ __u64 persist_fid, volatile_fid;
+ char *full_path;
+ FILE_ALL_INFO *data = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink)) {
+ FreeXid(xid);
+ return PTR_ERR(tlink);
+ }
+ tcon = tlink_tcon(tlink);
+
+ full_path = build_path_from_dentry(file->f_path.dentry);
+ if (full_path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ data = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+ if (data == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = smb2_open_helper(file, inode, full_path, &oplock, &persist_fid,
+ &volatile_fid, data, tcon, xid);
+ if (rc)
+ goto out;
+
+ rc = smb2_query_inode_info(&inode, full_path, data, inode->i_sb, xid);
+ if (rc) {
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ goto out;
+ }
+
+ cifs_file = smb2_new_fileinfo(persist_fid, volatile_fid, file, tlink,
+ oplock);
+ if (cifs_file == NULL) {
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ cifs_fscache_set_inode_cookie(inode, file);
+out:
+ kfree(full_path);
+ kfree(data);
+ FreeXid(xid);
+ cifs_put_tlink(tlink);
+ return rc;
+}
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 9111153..4b33f16 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -96,18 +96,18 @@ void smb2_set_ops(struct inode *inode)
inode->i_op = &smb2_file_inode_ops;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
- inode->i_fop = &cifs_file_direct_nobrl_ops;
+ inode->i_fop = &smb2_file_direct_nobrl_ops;
else
- inode->i_fop = &cifs_file_direct_ops;
+ inode->i_fop = &smb2_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
- inode->i_fop = &cifs_file_strict_nobrl_ops;
+ inode->i_fop = &smb2_file_strict_nobrl_ops;
else
- inode->i_fop = &cifs_file_strict_ops;
+ inode->i_fop = &smb2_file_strict_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
- inode->i_fop = &cifs_file_nobrl_ops;
+ inode->i_fop = &smb2_file_nobrl_ops;
else { /* not direct, send byte range locks */
- inode->i_fop = &cifs_file_ops;
+ inode->i_fop = &smb2_file_ops;
}
/* check if server can support readpages */
@@ -177,7 +177,7 @@ smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
return rc;
}
-static void
+void
move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src)
{
memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 891a51f..6bc3476 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1069,9 +1069,9 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
if (rc)
return rc;
- if (oplockEnabled)
+ /* if (enable_oplocks)
pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
- else
+ else */
pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
pSMB2->ImpersonationLevel = IL_IMPERSONATION;
pSMB2->DesiredAccess = cpu_to_le32(desired_access);
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2c5cf2c..b7d1f46 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -37,6 +37,13 @@ extern const struct inode_operations smb2_symlink_inode_ops;
extern const struct file_operations smb2_dir_ops;
+extern const struct file_operations smb2_file_ops;
+extern const struct file_operations smb2_file_direct_ops; /* if directio mnt */
+extern const struct file_operations smb2_file_strict_ops; /* if strictio mnt */
+extern const struct file_operations smb2_file_nobrl_ops; /* no brlocks */
+extern const struct file_operations smb2_file_direct_nobrl_ops;
+extern const struct file_operations smb2_file_strict_nobrl_ops;
+
/* extern char *build_smb2path_from_dentry(struct dentry *);*/
extern __le16 *build_ucspath_from_dentry(struct dentry *);
/*extern __le16 *smb2_build_path_to_root(struct cifs_sb_info *smb2_sb);
@@ -84,6 +91,7 @@ extern int smb2_setup_session(unsigned int xid, struct cifs_ses *pses_info,
struct nls_table *nls_info);
extern int smb2_umount(struct super_block *, struct cifs_sb_info *);
+extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src);
extern int smb2_query_inode_info(struct inode **pinode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid);
@@ -100,6 +108,13 @@ extern void smb2_create_dfs_attr(struct cifs_fattr *fattr,
extern void cifs_fattr_to_inode(struct inode *pinode, struct cifs_fattr *attr);
extern int smb2_fsync(struct file *file, int datasync);
extern int smb2_flush(struct file *file, fl_owner_t id);
+extern struct cifsFileInfo *smb2_new_fileinfo(__u64 persist_fid,
+ __u64 volatile_fid,
+ struct file *file,
+ struct tcon_link *tlink,
+ __u32 oplock);
+
+extern int smb2_open(struct inode *inode, struct file *file);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 23/53] CIFS: Add SMB2 support for reopen file operation
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (9 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 22/53] CIFS: Add SMB2 support for open/close file operations Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 25/53] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
` (12 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 4 ++
fs/cifs/file.c | 146 +++++++++++++++++++++++++++++++-------------------
fs/cifs/smb2file.c | 49 +++++++++++++++++
fs/cifs/smb2proto.h | 4 +-
4 files changed, 146 insertions(+), 57 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e6ea8de..82e40b2 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -596,6 +596,10 @@ struct cifsFileInfo {
struct work_struct oplock_break; /* work for oplock breaks */
};
+typedef int (reopen_callback_t)(struct cifsFileInfo *cifs_file, int xid,
+ struct cifs_tcon *tcon, const char *full_path,
+ __u32 *oplock);
+
struct cifs_io_parms {
__u16 netfid;
__u32 pid;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 37c8445..508ec3a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -484,53 +484,26 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
return rc;
}
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
+static int
+cifs_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
+ struct cifs_tcon *tcon, const char *full_path,
+ __u32 *oplock)
{
int rc = -EACCES;
- int xid;
- __u32 oplock;
struct cifs_sb_info *cifs_sb;
- struct cifs_tcon *tcon;
- struct cifsInodeInfo *pCifsInode;
struct inode *inode;
- char *full_path = NULL;
- int desiredAccess;
+ int desired_access;
int disposition = FILE_OPEN;
int create_options = CREATE_NOT_DIR;
__u16 netfid;
- xid = GetXid();
- mutex_lock(&pCifsFile->fh_mutex);
- if (!pCifsFile->invalidHandle) {
- mutex_unlock(&pCifsFile->fh_mutex);
- rc = 0;
- FreeXid(xid);
- return rc;
- }
-
- inode = pCifsFile->dentry->d_inode;
+ inode = cifs_file->dentry->d_inode;
cifs_sb = CIFS_SB(inode->i_sb);
- tcon = tlink_tcon(pCifsFile->tlink);
-
-/* 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);
- if (full_path == NULL) {
- rc = -ENOMEM;
- mutex_unlock(&pCifsFile->fh_mutex);
- FreeXid(xid);
- return rc;
- }
-
- cFYI(1, "inode = 0x%p file flags 0x%x for %s",
- inode, pCifsFile->f_flags, full_path);
if (enable_oplocks)
- oplock = REQ_OPLOCK;
+ *oplock = REQ_OPLOCK;
else
- oplock = 0;
+ *oplock = 0;
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
@@ -540,21 +513,23 @@ 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 &
- ~(O_CREAT | O_EXCL | O_TRUNC);
+ unsigned int oflags = cifs_file->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, &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(cifs_file->f_flags);
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
@@ -565,30 +540,78 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
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,
+ rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desired_access,
+ create_options, &netfid, oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
- mutex_unlock(&pCifsFile->fh_mutex);
cFYI(1, "cifs_open returned 0x%x", rc);
- cFYI(1, "oplock: %d", oplock);
+ cFYI(1, "oplock: %d", *oplock);
goto reopen_error_exit;
}
reopen_success:
- pCifsFile->netfid = netfid;
- pCifsFile->invalidHandle = false;
- mutex_unlock(&pCifsFile->fh_mutex);
- pCifsInode = CIFS_I(inode);
+ cifs_file->netfid = netfid;
+reopen_error_exit:
+ return rc;
+}
+
+static int
+cifs_reopen_file_generic(struct cifsFileInfo *cifs_file, bool can_flush,
+ reopen_callback_t *reopen_cb)
+{
+ int rc = -EACCES;
+ int xid;
+ __u32 oplock;
+ struct cifs_sb_info *cifs_sb;
+ struct cifs_tcon *tcon;
+ struct inode *inode;
+ struct cifsInodeInfo *cifs_inode;
+ char *full_path = NULL;
+
+ xid = GetXid();
+ mutex_lock(&cifs_file->fh_mutex);
+ if (!cifs_file->invalidHandle) {
+ mutex_unlock(&cifs_file->fh_mutex);
+ rc = 0;
+ FreeXid(xid);
+ return rc;
+ }
+
+ inode = cifs_file->dentry->d_inode;
+ cifs_sb = CIFS_SB(inode->i_sb);
+ tcon = tlink_tcon(cifs_file->tlink);
+
+ /*
+ * 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(cifs_file->dentry);
+ if (full_path == NULL) {
+ rc = -ENOMEM;
+ mutex_unlock(&cifs_file->fh_mutex);
+ FreeXid(xid);
+ return rc;
+ }
+
+ cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode,
+ cifs_file->f_flags, full_path);
+
+ rc = reopen_cb(cifs_file, xid, tcon, full_path, &oplock);
+ mutex_unlock(&cifs_file->fh_mutex);
+ if (rc)
+ goto out;
+ cifs_inode = 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);
@@ -599,16 +622,27 @@ reopen_success:
we can not go to the server to get the new inod
info */
- cifs_set_oplock_level(pCifsInode, oplock);
+ cifs_set_oplock_level(cifs_inode, oplock);
+ cifs_relock_file(cifs_file);
+ cifs_file->invalidHandle = false;
- cifs_relock_file(pCifsFile);
-
-reopen_error_exit:
+out:
kfree(full_path);
FreeXid(xid);
return rc;
}
+static int cifs_reopen_file(struct cifsFileInfo *cifs_file, bool can_flush)
+{
+#ifdef CONFIG_CIFS_SMB2
+ if (tlink_tcon(cifs_file->tlink)->ses->server->is_smb2)
+ return cifs_reopen_file_generic(cifs_file, can_flush,
+ smb2_reopen_file_cb);
+#endif
+ return cifs_reopen_file_generic(cifs_file, can_flush,
+ cifs_reopen_file_cb);
+}
+
int cifs_close(struct inode *inode, struct file *file)
{
if (file->private_data != NULL) {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 8b4d802..7284d40 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -272,3 +272,52 @@ out:
cifs_put_tlink(tlink);
return rc;
}
+
+int
+smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
+ struct cifs_tcon *tcon, const char *full_path,
+ __u32 *oplock)
+{
+ int rc = -EACCES;
+ struct cifs_sb_info *cifs_sb;
+ struct inode *inode;
+ __u32 desired_access;
+ __u32 create_disposition = FILE_OPEN;
+ __le16 *smb2_path = NULL;
+ __u64 persist_fid, volatile_fid;
+
+ inode = cifs_file->dentry->d_inode;
+ cifs_sb = CIFS_SB(inode->i_sb);
+
+ desired_access = cifs_convert_flags(cifs_file->f_flags);
+
+ /*
+ * Can not refresh inode by passing in file_info buf to be returned
+ * by SMB2_open 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.
+ */
+
+ smb2_path = cifs_convert_path_to_ucs(full_path, cifs_sb->local_nls);
+ if (smb2_path == NULL) {
+ rc = -ENOMEM;
+ goto reopen_error_exit;
+ }
+
+ rc = SMB2_open(xid, tcon, smb2_path, &persist_fid, &volatile_fid,
+ desired_access, create_disposition, 0, 0);
+ if (rc) {
+ mutex_unlock(&cifs_file->fh_mutex);
+ cFYI(1, "cifs_open returned 0x%x", rc);
+ cFYI(1, "oplock: %d", *oplock);
+ goto reopen_error_exit;
+ }
+
+ cifs_file->persist_fid = persist_fid;
+ cifs_file->volatile_fid = volatile_fid;
+ *oplock = 0;
+reopen_error_exit:
+ kfree(smb2_path);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index b7d1f46..40d0cae 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -113,9 +113,11 @@ extern struct cifsFileInfo *smb2_new_fileinfo(__u64 persist_fid,
struct file *file,
struct tcon_link *tlink,
__u32 oplock);
+extern int smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
+ struct cifs_tcon *tcon, const char *full_path,
+ __u32 *oplock);
extern int smb2_open(struct inode *inode, struct file *file);
-
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 24/53] CIFS: Add SMB2 support for cifs_iovec_write
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (9 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 21/53] CIFS: Add SMB2 support for unlink operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 27/53] CIFS: Add read related address space operations for SMB2 Pavel Shilovsky
` (16 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsglob.h | 7 +++++++
fs/cifs/cifsproto.h | 4 ++++
fs/cifs/file.c | 41 +++++++++++++++++++++++++++++++----------
fs/cifs/smb2file.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
fs/cifs/smb2pdu.c | 38 +++++++++++++++++++-------------------
fs/cifs/smb2proto.h | 11 ++++++-----
6 files changed, 115 insertions(+), 36 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 82e40b2..852c8d2 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -602,12 +602,19 @@ typedef int (reopen_callback_t)(struct cifsFileInfo *cifs_file, int xid,
struct cifs_io_parms {
__u16 netfid;
+ __u64 persist_fid;
+ __u64 volatile_fid;
__u32 pid;
__u64 offset;
unsigned int length;
struct cifs_tcon *tcon;
};
+typedef int (iwrite_callback_t)(int, struct cifsFileInfo *,
+ struct cifs_io_parms *, unsigned int *,
+ struct kvec *, unsigned long, unsigned int,
+ int);
+
/*
* 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 142660f..596a9ab 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -184,6 +184,10 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
extern void cifs_umount(struct cifs_sb_info *);
extern void cifs_dfs_release_automount_timer(void);
+extern ssize_t cifs_iovec_write_generic(struct file *file,
+ const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset,
+ iwrite_callback_t *write_cb);
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 508ec3a..2063394 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2114,6 +2114,19 @@ error:
return rc;
}
+static int
+cifs_iwrite_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *written, struct kvec *iov, unsigned long nr_segs,
+ unsigned int remaining_bytes, int timeout)
+{
+ int rc;
+
+ parms->netfid = cfile->netfid;
+ rc = CIFSSMBWrite2(xid, parms, written, iov, nr_segs, timeout);
+
+ return rc;
+}
+
static inline
size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
{
@@ -2131,9 +2144,10 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
return num_pages;
}
-static ssize_t
-cifs_iovec_write(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *poffset)
+ssize_t
+cifs_iovec_write_generic(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset,
+ iwrite_callback_t *write_cb)
{
unsigned int written;
unsigned long num_pages, npages, i;
@@ -2144,7 +2158,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
struct iov_iter it;
struct inode *inode;
struct cifsFileInfo *open_file;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb;
struct cifs_io_parms io_parms;
int xid, rc;
@@ -2186,7 +2200,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
else
pid = current->tgid;
- pTcon = tlink_tcon(open_file->tlink);
+ tcon = tlink_tcon(open_file->tlink);
inode = file->f_path.dentry->d_inode;
iov_iter_init(&it, iov, nr_segs, len, 0);
@@ -2212,13 +2226,12 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
if (rc != 0)
break;
}
- 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 = cur_len;
- rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send,
- npages, 0);
+ rc = write_cb(xid, open_file, &io_parms, &written,
+ to_send, npages, len - total_written, 0);
} while (rc == -EAGAIN);
for (i = 0; i < npages; i++)
@@ -2246,7 +2259,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
spin_unlock(&inode->i_lock);
}
- cifs_stats_bytes_written(pTcon, total_written);
+ cifs_stats_bytes_written(tcon, total_written);
mark_inode_dirty_sync(inode);
for (i = 0; i < num_pages; i++)
@@ -2257,6 +2270,14 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
return total_written;
}
+static ssize_t
+cifs_iovec_write(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset)
+{
+ return cifs_iovec_write_generic(file, iov, nr_segs, poffset,
+ cifs_iwrite_cb);
+}
+
ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 7284d40..3a2b3e1 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -78,7 +78,7 @@ const struct file_operations smb2_file_direct_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_user_readv,
- .aio_write = cifs_user_writev,
+ .aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
.lock = cifs_lock,
@@ -134,7 +134,7 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_user_readv,
- .aio_write = cifs_user_writev,
+ .aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
.fsync = cifs_fsync,
@@ -321,3 +321,49 @@ reopen_error_exit:
kfree(smb2_path);
return rc;
}
+
+static int
+smb2_iwrite_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *written, struct kvec *iov, unsigned long nr_segs,
+ unsigned int remaining_bytes, int timeout)
+{
+ int rc;
+
+ parms->persist_fid = cfile->persist_fid;
+ parms->volatile_fid = cfile->volatile_fid;
+ rc = SMB2_write(xid, parms, written, iov, nr_segs, remaining_bytes,
+ timeout);
+
+ return rc;
+}
+
+static ssize_t
+smb2_iovec_write(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset)
+{
+ return cifs_iovec_write_generic(file, iov, nr_segs, poffset,
+ smb2_iwrite_cb);
+}
+
+ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ ssize_t written;
+ struct inode *inode;
+
+ inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+ /*
+ * BB - optimize the way when signing is disabled. We can drop this
+ * extra memory-to-memory copying and use iovec buffers for constructing
+ * write request.
+ */
+
+ written = smb2_iovec_write(iocb->ki_filp, iov, nr_segs, &pos);
+ if (written > 0) {
+ CIFS_I(inode)->invalid_mapping = true;
+ iocb->ki_pos = pos;
+ }
+
+ return written;
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6bc3476..f77b861 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2364,15 +2364,13 @@ int SMB2_read(const int xid, struct cifs_tcon *tcon,
/*
* SMB2_write function gets iov pointer to kvec array with n_vec as a length.
- * The length must be at least 2 because the first element of the array is
- * SMB2 header. Other elements contain a data to write, its length is specified
- * by count.
+ * 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 int xid, struct cifs_tcon *tcon,
- const u64 persistent_fid, const u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int *nbytes, struct kvec *iov, int n_vec,
- const unsigned int remaining_bytes, int wtimeout)
+int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec,
+ const unsigned int remaining_bytes, int wtimeout)
{
int rc = 0;
struct write_req *pSMB2 = NULL;
@@ -2380,23 +2378,25 @@ int SMB2_write(const int xid, struct cifs_tcon *tcon,
int status, resp_buftype;
*nbytes = 0;
- if (n_vec < 2)
+ if (n_vec < 1)
return rc;
- rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &pSMB2);
+ rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &pSMB2);
if (rc)
return rc;
- if (tcon->ses->server == NULL)
+ if (io_parms->tcon->ses->server == NULL)
return -ECONNABORTED;
- pSMB2->PersistentFileId = persistent_fid;
- pSMB2->VolatileFileId = volatile_fid;
+ pSMB2->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+ pSMB2->PersistentFileId = io_parms->persist_fid;
+ pSMB2->VolatileFileId = io_parms->volatile_fid;
pSMB2->WriteChannelInfoOffset = 0;
pSMB2->WriteChannelInfoLength = 0;
pSMB2->Channel = 0;
- pSMB2->Length = cpu_to_le32(count);
- pSMB2->Offset = cpu_to_le64(lseek);
+ pSMB2->Length = cpu_to_le32(io_parms->length);
+ pSMB2->Offset = cpu_to_le64(io_parms->offset);
pSMB2->DataOffset = cpu_to_le16(offsetof(struct write_req, Buffer) - 4);
pSMB2->RemainingBytes = 0;
@@ -2406,16 +2406,16 @@ int SMB2_write(const int xid, struct cifs_tcon *tcon,
/* length of entire message including data to be written */
pSMB2->hdr.smb2_buf_length =
cpu_to_be32(be32_to_cpu(pSMB2->hdr.smb2_buf_length)
- - 1 /* pad */ + count);
+ - 1 /* pad */ + io_parms->length);
- rc = smb2_sendrcv2(xid, tcon->ses, iov, n_vec, &resp_buftype, &status,
- wtimeout | CIFS_LOG_ERROR);
+ rc = smb2_sendrcv2(xid, io_parms->tcon->ses, iov, n_vec + 1,
+ &resp_buftype, &status, wtimeout | CIFS_LOG_ERROR);
cFYI(1, "write returned buftype %d with rc %d status 0x%x",
resp_buftype, rc, status);
if (rc) {
- cifs_stats_fail_inc(tcon, SMB2WRITE);
+ cifs_stats_fail_inc(io_parms->tcon, SMB2WRITE);
cERROR(1, "Send error in write = %d", rc);
} else {
pSMB2r = (struct write_rsp *)iov[0].iov_base;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 40d0cae..ede6ee9 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -118,6 +118,9 @@ extern int smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
__u32 *oplock);
extern int smb2_open(struct inode *inode, struct file *file);
+extern ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
+
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
@@ -183,11 +186,9 @@ extern int SMB2_read(const int xid, struct cifs_tcon *tcon,
const unsigned int count, const __u64 lseek,
unsigned int *nbytes, char **buf, int *pbuf_type,
unsigned int remaining_bytes);
-extern int SMB2_write(const int xid, struct cifs_tcon *tcon,
- const u64 persistent_fid, const u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int *nbytes, struct kvec *iov, int n_vec,
- const unsigned int remaining_bytes, int wtimeout);
+extern int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec,
+ const unsigned int remaining_bytes, int wtimeout);
extern int SMB2_write_complex(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
const unsigned int count, const __u64 lseek,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 25/53] CIFS: Add SMB2 support for cifs_iovec_read
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (10 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 23/53] CIFS: Add SMB2 support for reopen file operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 26/53] CIFS: Add address space ops structures for SMB2 Pavel Shilovsky
` (11 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 3 ++
fs/cifs/cifsproto.h | 4 +++
fs/cifs/file.c | 76 +++++++++++++++++++++++++++++++++-----------------
fs/cifs/smb2file.c | 43 +++++++++++++++++++++++++++-
fs/cifs/smb2pdu.c | 47 +++++++++++++++-----------------
fs/cifs/smb2proto.h | 17 +++++-------
6 files changed, 127 insertions(+), 63 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 852c8d2..1ab2767 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -614,6 +614,9 @@ typedef int (iwrite_callback_t)(int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *,
struct kvec *, unsigned long, unsigned int,
int);
+typedef int (iread_callback_t)(int, struct cifsFileInfo *,
+ struct cifs_io_parms *, unsigned int *, char **,
+ char **, int *);
/*
* Take a reference on the file private data. Must be called with
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 596a9ab..1129f16 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -188,6 +188,10 @@ extern ssize_t cifs_iovec_write_generic(struct file *file,
const struct iovec *iov,
unsigned long nr_segs, loff_t *poffset,
iwrite_callback_t *write_cb);
+extern ssize_t cifs_iovec_read_generic(struct file *file,
+ const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset,
+ iread_callback_t *read_cb);
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2063394..44f678a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2340,9 +2340,28 @@ ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return written;
}
-static ssize_t
-cifs_iovec_read(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *poffset)
+static int
+cifs_iread_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *bytes_read, char **all_data, char **data_offset,
+ int *resp_buf_type)
+{
+ struct smb_com_read_rsp *pSMBr;
+ int rc;
+
+ parms->netfid = cfile->netfid;
+ rc = CIFSSMBRead(xid, parms, bytes_read, all_data, resp_buf_type);
+ if (!(*all_data))
+ return rc;
+
+ pSMBr = (struct smb_com_read_rsp *)(*all_data);
+ *data_offset = *all_data + 4 + le16_to_cpu(pSMBr->DataOffset);
+ return rc;
+}
+
+ssize_t
+cifs_iovec_read_generic(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset,
+ iread_callback_t *read_cb)
{
int rc;
int xid;
@@ -2351,11 +2370,11 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
size_t len, cur_len;
int iov_offset = 0;
struct cifs_sb_info *cifs_sb;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
struct cifsFileInfo *open_file;
- struct smb_com_read_rsp *pSMBr;
struct cifs_io_parms io_parms;
char *read_data;
+ char *data_offset = NULL;
unsigned int rsize;
__u32 pid;
@@ -2373,7 +2392,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
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;
@@ -2395,27 +2414,24 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
if (rc != 0)
break;
}
- 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 = cur_len;
- rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
- &read_data, &buf_type);
- pSMBr = (struct smb_com_read_rsp *)read_data;
- if (read_data) {
- char *data_offset = read_data + 4 +
- le16_to_cpu(pSMBr->DataOffset);
- if (memcpy_toiovecend(iov, data_offset,
- iov_offset, bytes_read))
- rc = -EFAULT;
- if (buf_type == CIFS_SMALL_BUFFER)
- cifs_small_buf_release(read_data);
- else if (buf_type == CIFS_LARGE_BUFFER)
- cifs_buf_release(read_data);
- read_data = NULL;
- iov_offset += bytes_read;
- }
+ rc = read_cb(xid, open_file, &io_parms, &bytes_read,
+ &read_data, &data_offset, &buf_type);
+ if (rc)
+ continue;
+
+ if (memcpy_toiovecend(iov, data_offset,
+ iov_offset, bytes_read))
+ rc = -EFAULT;
+ if (buf_type == CIFS_SMALL_BUFFER)
+ cifs_small_buf_release(read_data);
+ else if (buf_type == CIFS_LARGE_BUFFER)
+ cifs_buf_release(read_data);
+ read_data = NULL;
+ iov_offset += bytes_read;
}
if (rc || (bytes_read == 0)) {
@@ -2426,7 +2442,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
return rc;
}
} else {
- cifs_stats_bytes_read(pTcon, bytes_read);
+ cifs_stats_bytes_read(tcon, bytes_read);
*poffset += bytes_read;
}
}
@@ -2435,8 +2451,16 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
return total_read;
}
+static ssize_t
+cifs_iovec_read(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset)
+{
+ return cifs_iovec_read_generic(file, iov, nr_segs, poffset,
+ cifs_iread_cb);
+}
+
ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
+ unsigned long nr_segs, loff_t pos)
{
ssize_t read;
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 3a2b3e1..3404d8a 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -77,7 +77,7 @@ const struct file_operations smb2_file_direct_ops = {
/* BB reevaluate whether they can be done with directio, no cache */
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = cifs_user_readv,
+ .aio_read = smb2_user_readv,
.aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
@@ -133,7 +133,7 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
/* BB reevaluate whether they can be done with directio, no cache */
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = cifs_user_readv,
+ .aio_read = smb2_user_readv,
.aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
@@ -367,3 +367,42 @@ ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
return written;
}
+
+static int
+smb2_iread_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *bytes_read, char **all_data, char **data_offset,
+ int *resp_buf_type)
+{
+ struct read_rsp *pSMB2r;
+ int rc;
+
+ parms->persist_fid = cfile->persist_fid;
+ parms->volatile_fid = cfile->volatile_fid;
+ rc = SMB2_read(xid, parms, bytes_read, all_data, resp_buf_type, 0);
+ if (!(*all_data))
+ return rc;
+
+ pSMB2r = (struct read_rsp *)(*all_data);
+ *data_offset = (char *)pSMB2r->hdr.ProtocolId + pSMB2r->DataOffset;
+ return rc;
+}
+
+static ssize_t
+smb2_iovec_read(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset)
+{
+ return cifs_iovec_read_generic(file, iov, nr_segs, poffset,
+ smb2_iread_cb);
+}
+
+ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ ssize_t read;
+
+ read = smb2_iovec_read(iocb->ki_filp, iov, nr_segs, &pos);
+ if (read > 0)
+ iocb->ki_pos = pos;
+
+ return read;
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index f77b861..2ff0acf 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2259,29 +2259,28 @@ rename_exit:
* To form a chain of read requests, any read requests after the
* first should have the end_of_chain boolean set to true.
*/
-int new_read_req(struct kvec *iov, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int remaining_bytes,
- int request_type)
+int new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+ unsigned int remaining_bytes, int request_type)
{
int rc = -EACCES;
struct read_req *pSMB2 = NULL;
- rc = small_smb2_init(SMB2_READ, tcon, (void **) &pSMB2);
+ rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &pSMB2);
if (rc)
return rc;
- if (tcon->ses->server == NULL)
+ if (io_parms->tcon->ses->server == NULL)
return -ECONNABORTED;
- pSMB2->PersistentFileId = persistent_fid;
- pSMB2->VolatileFileId = volatile_fid;
+ pSMB2->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+ pSMB2->PersistentFileId = io_parms->persist_fid;
+ pSMB2->VolatileFileId = io_parms->volatile_fid;
pSMB2->ReadChannelInfoOffset = 0; /* reserved */
pSMB2->ReadChannelInfoLength = 0; /* reserved */
pSMB2->Channel = 0; /* reserved */
pSMB2->MinimumCount = 0;
- pSMB2->Length = cpu_to_le32(count);
- pSMB2->Offset = cpu_to_le64(lseek);
+ pSMB2->Length = cpu_to_le32(io_parms->length);
+ pSMB2->Offset = cpu_to_le64(io_parms->offset);
if (request_type & CHAINED_REQUEST) {
if (!(request_type & END_OF_CHAIN)) {
@@ -2301,7 +2300,7 @@ int new_read_req(struct kvec *iov, struct cifs_tcon *tcon,
pSMB2->VolatileFileId = 0xFFFFFFFF;
}
}
- if (remaining_bytes > count)
+ if (remaining_bytes > io_parms->length)
pSMB2->RemainingBytes = cpu_to_le32(remaining_bytes);
else
pSMB2->RemainingBytes = 0;
@@ -2311,22 +2310,20 @@ int new_read_req(struct kvec *iov, struct cifs_tcon *tcon,
return rc;
}
-int SMB2_read(const int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int *nbytes, char **buf, int *pbuf_type,
- unsigned int remaining_bytes)
+int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *pbuf_type,
+ unsigned int remaining_bytes)
{
int status, resp_buftype, rc = -EACCES;
struct read_rsp *pSMB2r = NULL;
struct kvec iov[1];
*nbytes = 0;
- rc = new_read_req(iov, tcon, persistent_fid, volatile_fid,
- count, lseek, remaining_bytes, 0);
+ rc = new_read_req(iov, io_parms, remaining_bytes, 0);
if (rc)
return rc;
- rc = smb2_sendrcv2(xid, tcon->ses, iov, 1,
+
+ rc = smb2_sendrcv2(xid, io_parms->tcon->ses, iov, 1,
&resp_buftype, &status,
CIFS_STD_OP | CIFS_LOG_ERROR);
if (status == STATUS_END_OF_FILE) {
@@ -2340,14 +2337,14 @@ int SMB2_read(const int xid, struct cifs_tcon *tcon,
pSMB2r = (struct read_rsp *)iov[0].iov_base;
if (rc) {
- cifs_stats_fail_inc(tcon, SMB2READ);
+ cifs_stats_fail_inc(io_parms->tcon, SMB2READ);
cERROR(1, "Send error in read = %d", rc);
} else {
*nbytes = le32_to_cpu(pSMB2r->DataLength);
- if ((*nbytes > SMB2_MAX_MSGSIZE)
- || (*nbytes > count)) {
- cFYI(1, "bad length %d for count %d",
- *nbytes, count);
+ if ((*nbytes > SMB2_MAX_MSGSIZE) ||
+ (*nbytes > io_parms->length)) {
+ cFYI(1, "bad length %d for count %d", *nbytes,
+ io_parms->length);
rc = -EIO;
*nbytes = 0;
}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index ede6ee9..30ab741 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -118,6 +118,8 @@ extern int smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
__u32 *oplock);
extern int smb2_open(struct inode *inode, struct file *file);
+extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
@@ -181,11 +183,9 @@ extern int SMB2_symlink_ioctl(const int, struct cifs_tcon *, u32, u64, u64,
const char *);
extern int SMB2_close(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id);
-extern int SMB2_read(const int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int *nbytes, char **buf, int *pbuf_type,
- unsigned int remaining_bytes);
+extern int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *pbuf_type,
+ unsigned int remaining_bytes);
extern int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec,
const unsigned int remaining_bytes, int wtimeout);
@@ -209,11 +209,8 @@ extern int SMB2_lock(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
u64 length, u64 offset, u32 lockFlags, int wait);
extern void DeleteMidQEntryComplex(struct mid_q_entry *midEntry);
-extern int new_read_req(struct kvec *iov, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- const unsigned int count, const __u64 lseek,
- unsigned int remaining_bytes,
- int request_type);
+extern int new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+ unsigned int remaining_bytes, int request_type);
extern int smb2_sendv(struct TCP_Server_Info *server, struct kvec *iov,
int n_vec);
extern int smb2_wait_on_complex_mid(struct cifs_ses *ses,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 26/53] CIFS: Add address space ops structures for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (11 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 25/53] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 28/53] CIFS: Add write related address space operations " Pavel Shilovsky
` (10 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsproto.h | 15 +++++++++++++++
fs/cifs/file.c | 28 ++++++++++++++--------------
fs/cifs/smb2file.c | 30 ++++++++++++++++++++++++++++++
fs/cifs/smb2inode.c | 4 ++--
fs/cifs/smb2proto.h | 3 +++
5 files changed, 64 insertions(+), 16 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1129f16..eee59f7 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -193,6 +193,21 @@ extern ssize_t cifs_iovec_read_generic(struct file *file,
unsigned long nr_segs, loff_t *poffset,
iread_callback_t *read_cb);
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
+extern int cifs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata);
+extern int cifs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
+extern int cifs_release_page(struct page *page, gfp_t gfp);
+extern void cifs_invalidate_page(struct page *page, unsigned long offset);
+extern int cifs_launder_page(struct page *page);
+extern int cifs_readpage(struct file *file, struct page *page);
+extern int cifs_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages);
+extern int cifs_writepages(struct address_space *mapping,
+ struct writeback_control *wbc);
+extern int cifs_writepage(struct page *page, struct writeback_control *wbc);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 44f678a..6eb1741 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1699,7 +1699,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
return rc;
}
-static int cifs_writepages(struct address_space *mapping,
+int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb);
@@ -1937,16 +1937,16 @@ retry_write:
return rc;
}
-static int cifs_writepage(struct page *page, struct writeback_control *wbc)
+int cifs_writepage(struct page *page, struct writeback_control *wbc)
{
int rc = cifs_writepage_locked(page, wbc);
unlock_page(page);
return rc;
}
-static int cifs_write_end(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
+int cifs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
+ unsigned len, unsigned copied, struct page *page,
+ void *fsdata)
{
int rc;
struct inode *inode = mapping->host;
@@ -2631,8 +2631,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
return rc;
}
-static int cifs_readpages(struct file *file, struct address_space *mapping,
- struct list_head *page_list, unsigned num_pages)
+int cifs_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages)
{
int rc;
struct list_head tmplist;
@@ -2825,7 +2825,7 @@ read_complete:
return rc;
}
-static int cifs_readpage(struct file *file, struct page *page)
+int cifs_readpage(struct file *file, struct page *page)
{
loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
int rc = -EACCES;
@@ -2895,9 +2895,9 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
return true;
}
-static int cifs_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
+int cifs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
{
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
@@ -2967,7 +2967,7 @@ out:
return rc;
}
-static int cifs_release_page(struct page *page, gfp_t gfp)
+int cifs_release_page(struct page *page, gfp_t gfp)
{
if (PagePrivate(page))
return 0;
@@ -2975,7 +2975,7 @@ static int cifs_release_page(struct page *page, gfp_t gfp)
return cifs_fscache_release_page(page, gfp);
}
-static void cifs_invalidate_page(struct page *page, unsigned long offset)
+void cifs_invalidate_page(struct page *page, unsigned long offset)
{
struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
@@ -2983,7 +2983,7 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset)
cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
}
-static int cifs_launder_page(struct page *page)
+int cifs_launder_page(struct page *page)
{
int rc = 0;
loff_t range_start = page_offset(page);
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 3404d8a..1091934 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -148,6 +148,36 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
.setlease = cifs_setlease,
};
+const struct address_space_operations smb2_addr_ops = {
+ .readpage = cifs_readpage,
+ .readpages = cifs_readpages,
+ .writepage = cifs_writepage,
+ .writepages = cifs_writepages,
+ .write_begin = cifs_write_begin,
+ .write_end = cifs_write_end,
+ .set_page_dirty = __set_page_dirty_nobuffers,
+ .releasepage = cifs_release_page,
+ .invalidatepage = cifs_invalidate_page,
+ .launder_page = cifs_launder_page,
+};
+
+/*
+ * cifs_readpages requires the server to support a buffer large enough to
+ * contain the header plus one complete page of data. Otherwise, we need
+ * to leave cifs_readpages out of the address space operations.
+ */
+const struct address_space_operations smb2_addr_ops_smallbuf = {
+ .readpage = cifs_readpage,
+ .writepage = cifs_writepage,
+ .writepages = cifs_writepages,
+ .write_begin = cifs_write_begin,
+ .write_end = cifs_write_end,
+ .set_page_dirty = __set_page_dirty_nobuffers,
+ .releasepage = cifs_release_page,
+ .invalidatepage = cifs_invalidate_page,
+ .launder_page = cifs_launder_page,
+};
+
struct cifsFileInfo *
smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
struct tcon_link *tlink, __u32 oplock)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 4b33f16..1d21185 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -113,9 +113,9 @@ void smb2_set_ops(struct inode *inode)
/* check if server can support readpages */
if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
PAGE_CACHE_SIZE)
- inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+ inode->i_data.a_ops = &smb2_addr_ops_smallbuf;
else
- inode->i_data.a_ops = &cifs_addr_ops;
+ inode->i_data.a_ops = &smb2_addr_ops;
break;
case S_IFDIR:
#ifdef CONFIG_CIFS_DFS_UPCALL
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 30ab741..810a7fc 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -44,6 +44,9 @@ extern const struct file_operations smb2_file_nobrl_ops; /* no brlocks */
extern const struct file_operations smb2_file_direct_nobrl_ops;
extern const struct file_operations smb2_file_strict_nobrl_ops;
+extern const struct address_space_operations smb2_addr_ops;
+extern const struct address_space_operations smb2_addr_ops_smallbuf;
+
/* extern char *build_smb2path_from_dentry(struct dentry *);*/
extern __le16 *build_ucspath_from_dentry(struct dentry *);
/*extern __le16 *smb2_build_path_to_root(struct cifs_sb_info *smb2_sb);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 27/53] CIFS: Add read related address space operations for SMB2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (10 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 24/53] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 29/53] CIFS: Respect max buf size for SMB2 read and write Pavel Shilovsky
` (15 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
and temporarily disable readpages support.
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +++
fs/cifs/file.c | 34 +++++++++++++++++++++++++++++-----
fs/cifs/smb2file.c | 13 ++++++++++++-
fs/cifs/smb2pdu.c | 20 +++++++++++++++-----
fs/cifs/smb2proto.h | 4 ++++
5 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1ab2767..465e87c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -617,6 +617,9 @@ typedef int (iwrite_callback_t)(int, struct cifsFileInfo *,
typedef int (iread_callback_t)(int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *, char **,
char **, int *);
+typedef int (read_callback_t)(int, struct cifsFileInfo *,
+ struct cifs_io_parms *, unsigned int *, char **,
+ int *, unsigned int);
/*
* Take a reference on the file private data. Must be called with
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6eb1741..f20b38c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2493,8 +2493,9 @@ 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_generic(struct file *file, char *read_data, size_t read_size,
+ loff_t *poffset, read_callback_t *read_cb)
{
int rc = -EACCES;
unsigned int bytes_read = 0;
@@ -2551,13 +2552,12 @@ 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.pid = pid;
io_parms.tcon = pTcon;
io_parms.offset = *poffset;
io_parms.length = current_read_size;
- rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
- ¤t_offset, &buf_type);
+ rc = read_cb(xid, open_file, &io_parms, &bytes_read,
+ ¤t_offset, &buf_type, 0);
}
if (rc || (bytes_read == 0)) {
if (total_read) {
@@ -2575,6 +2575,30 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return total_read;
}
+static int
+cifs_read_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *bytes_read, char **buf, int *buf_type,
+ unsigned int remaining_bytes)
+{
+ parms->netfid = cfile->netfid;
+ return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
+}
+
+static ssize_t
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
+{
+#ifdef CONFIG_CIFS_SMB2
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
+
+ if (tlink_tcon(cfile->tlink)->ses->server->is_smb2)
+ return cifs_read_generic(file, read_data, read_size, offset,
+ smb2_read_cb);
+#endif
+
+ return cifs_read_generic(file, read_data, read_size, offset,
+ cifs_read_cb);
+}
+
/*
* If the page is mmap'ed into a process' page tables, then we need to make
* sure that it doesn't change while being written back.
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 1091934..b17e71c 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -150,7 +150,7 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
const struct address_space_operations smb2_addr_ops = {
.readpage = cifs_readpage,
- .readpages = cifs_readpages,
+ /*.readpages = cifs_readpages,*/
.writepage = cifs_writepage,
.writepages = cifs_writepages,
.write_begin = cifs_write_begin,
@@ -436,3 +436,14 @@ ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
return read;
}
+
+int
+smb2_read_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *bytes_read, char **buf, int *buf_type,
+ unsigned int remaining_bytes)
+{
+ parms->persist_fid = cfile->persist_fid;
+ parms->volatile_fid = cfile->volatile_fid;
+ return SMB2_read(xid, parms, bytes_read, buf, buf_type,
+ remaining_bytes);
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2ff0acf..8d13b34 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2311,7 +2311,7 @@ int new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
}
int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, char **buf, int *pbuf_type,
+ unsigned int *nbytes, char **buf, int *buf_type,
unsigned int remaining_bytes)
{
int status, resp_buftype, rc = -EACCES;
@@ -2349,12 +2349,22 @@ int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
*nbytes = 0;
}
}
- if (resp_buftype != CIFS_NO_BUFFER) {
- *buf = iov[0].iov_base;
+
+ if (*buf) {
+ memcpy(*buf, (char *)pSMB2r->hdr.ProtocolId +
+ pSMB2r->DataOffset, *nbytes);
if (resp_buftype == CIFS_SMALL_BUFFER)
- *pbuf_type = CIFS_SMALL_BUFFER;
+ cifs_small_buf_release(iov[0].iov_base);
else if (resp_buftype == CIFS_LARGE_BUFFER)
- *pbuf_type = CIFS_LARGE_BUFFER;
+ cifs_buf_release(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;
}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 810a7fc..d891915 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -119,6 +119,10 @@ extern struct cifsFileInfo *smb2_new_fileinfo(__u64 persist_fid,
extern int smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
struct cifs_tcon *tcon, const char *full_path,
__u32 *oplock);
+extern int smb2_read_cb(int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *bytes_read,
+ char **buf, int *buf_type,
+ unsigned int remaining_bytes);
extern int smb2_open(struct inode *inode, struct file *file);
extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 28/53] CIFS: Add write related address space operations for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (12 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 26/53] CIFS: Add address space ops structures for SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 30/53] CIFS: Temporarily disable set inode info " Pavel Shilovsky
` (9 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
and temporarily disable writepages support.
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/file.c | 35 +++++++++++++++++++++++++++++------
fs/cifs/smb2file.c | 16 ++++++++++++++--
fs/cifs/smb2proto.h | 4 ++++
3 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f20b38c..4e9616d 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1461,9 +1461,10 @@ 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_generic(struct cifsFileInfo *open_file, __u32 pid,
+ const char *write_data, size_t write_size, loff_t *poffset,
+ iwrite_callback_t *write_cb)
{
int rc = 0;
unsigned int bytes_written = 0;
@@ -1506,13 +1507,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->netfid;
io_parms.pid = pid;
io_parms.tcon = pTcon;
io_parms.offset = *poffset;
io_parms.length = len;
- rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
- 1, 0);
+ rc = write_cb(xid, open_file, &io_parms, &bytes_written,
+ iov, 1, write_size - total_written, 0);
}
if (rc || (bytes_written == 0)) {
if (total_written)
@@ -1540,6 +1540,29 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
return total_written;
}
+static int cifs_write_cb(int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *written,
+ struct kvec *iov, unsigned long nr_segs,
+ unsigned int remaining_bytes, int timeout)
+{
+
+ parms->netfid = cfile->netfid;
+ return CIFSSMBWrite2(xid, parms, written, iov, nr_segs, timeout);
+}
+
+static ssize_t
+cifs_write(struct cifsFileInfo *cfile, __u32 pid, const char *write_data,
+ size_t write_size, loff_t *offset)
+{
+#ifdef CONFIG_CIFS_SMB2
+ if (tlink_tcon(cfile->tlink)->ses->server->is_smb2)
+ return cifs_write_generic(cfile, pid, write_data, write_size,
+ offset, smb2_write_cb);
+#endif
+ return cifs_write_generic(cfile, pid, write_data, write_size, offset,
+ cifs_write_cb);
+}
+
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only)
{
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index b17e71c..40f05e4 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -152,7 +152,7 @@ const struct address_space_operations smb2_addr_ops = {
.readpage = cifs_readpage,
/*.readpages = cifs_readpages,*/
.writepage = cifs_writepage,
- .writepages = cifs_writepages,
+ /*.writepages = cifs_writepages,*/
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
@@ -169,7 +169,7 @@ const struct address_space_operations smb2_addr_ops = {
const struct address_space_operations smb2_addr_ops_smallbuf = {
.readpage = cifs_readpage,
.writepage = cifs_writepage,
- .writepages = cifs_writepages,
+ /*.writepages = cifs_writepages,*/
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
@@ -447,3 +447,15 @@ smb2_read_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
return SMB2_read(xid, parms, bytes_read, buf, buf_type,
remaining_bytes);
}
+
+int
+smb2_write_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
+ unsigned int *written, struct kvec *iov, unsigned long nr_segs,
+ unsigned int remaining_bytes, int timeout)
+{
+
+ parms->persist_fid = cfile->persist_fid;
+ parms->volatile_fid = cfile->volatile_fid;
+ return SMB2_write(xid, parms, written, iov, nr_segs,
+ remaining_bytes, timeout);
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index d891915..7798626 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -123,6 +123,10 @@ extern int smb2_read_cb(int xid, struct cifsFileInfo *cfile,
struct cifs_io_parms *parms, unsigned int *bytes_read,
char **buf, int *buf_type,
unsigned int remaining_bytes);
+extern int smb2_write_cb(int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *written,
+ struct kvec *iov, unsigned long nr_segs,
+ unsigned int remaining_bytes, int timeout);
extern int smb2_open(struct inode *inode, struct file *file);
extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 29/53] CIFS: Respect max buf size for SMB2 read and write
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (11 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 27/53] CIFS: Add read related address space operations for SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 34/53] [CIFS] Add SMB2 support for cifs_get_file_info Pavel Shilovsky
` (14 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/connect.c | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 0187f11..62edb10 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3078,6 +3078,18 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
CIFS_DEFAULT_IOSIZE;
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2) {
+ 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;
+ }
+#endif
+
/* 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);
@@ -3106,6 +3118,20 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
struct TCP_Server_Info *server = tcon->ses->server;
unsigned int rsize, defsize;
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2) {
+ rsize = pvolume_info->rsize ? pvolume_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;
+ }
+#endif
+
/*
* Set default value...
*
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 30/53] CIFS: Temporarily disable set inode info for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (13 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 28/53] CIFS: Add write related address space operations " Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 31/53] CIFS: Add writepages support " Pavel Shilovsky
` (8 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/inode.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ba175ad..a465d04 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -2309,9 +2309,14 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
{
struct inode *inode = direntry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
- if (pTcon->unix_ext)
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2)
+ return 0;
+#endif
+
+ if (tcon->unix_ext)
return cifs_setattr_unix(direntry, attrs);
return cifs_setattr_nounix(direntry, attrs);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 31/53] CIFS: Add writepages support for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (14 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 30/53] CIFS: Temporarily disable set inode info " Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 32/53] CIFS: Add readpages " Pavel Shilovsky
` (7 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 17 +++++++
fs/cifs/cifsproto.h | 17 ++-----
fs/cifs/cifssmb.c | 5 +-
fs/cifs/file.c | 14 ++++-
fs/cifs/smb2file.c | 10 +++-
fs/cifs/smb2pdu.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 12 +++++
fs/cifs/smb2transport.c | 67 +++++++++++++++++++++++++-
8 files changed, 242 insertions(+), 22 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 465e87c..54125cc 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -600,6 +600,23 @@ typedef int (reopen_callback_t)(struct cifsFileInfo *cifs_file, int xid,
struct cifs_tcon *tcon, const char *full_path,
__u32 *oplock);
+struct cifs_writedata;
+typedef int (awritev_callback_t)(struct cifs_writedata *);
+
+/* asynchronous write support */
+struct cifs_writedata {
+ struct kref refcount;
+ enum writeback_sync_modes sync_mode;
+ struct work_struct work;
+ awritev_callback_t *requeue_writev;
+ struct cifsFileInfo *cfile;
+ __u64 offset;
+ unsigned int bytes;
+ int result;
+ unsigned int nr_pages;
+ struct page *pages[1];
+};
+
struct cifs_io_parms {
__u16 netfid;
__u64 persist_fid;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index eee59f7..6cf4313 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -207,10 +207,14 @@ extern int cifs_readpages(struct file *file, struct address_space *mapping,
struct list_head *page_list, unsigned num_pages);
extern int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc);
+extern int cifs_writepages_generic(struct address_space *mapping,
+ struct writeback_control *wbc,
+ awritev_callback_t *async_writev);
extern int cifs_writepage(struct page *page, struct writeback_control *wbc);
void cifs_proc_init(void);
void cifs_proc_clean(void);
+extern void inc_rfc1001_len(void *pSMB, int count);
extern int cifs_negotiate_protocol(unsigned int xid,
struct cifs_ses *ses);
extern int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
@@ -509,19 +513,6 @@ struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages);
void cifs_readdata_free(struct cifs_readdata *rdata);
int cifs_async_readv(struct cifs_readdata *rdata);
-/* asynchronous write support */
-struct cifs_writedata {
- struct kref refcount;
- enum writeback_sync_modes sync_mode;
- struct work_struct work;
- struct cifsFileInfo *cfile;
- __u64 offset;
- unsigned int bytes;
- int result;
- unsigned int nr_pages;
- struct page *pages[1];
-};
-
int cifs_async_writev(struct cifs_writedata *wdata);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages);
void cifs_writedata_release(struct kref *refcount);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index bc13c8b..0c73678 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -365,7 +365,7 @@ vt2_err:
return -EINVAL;
}
-static inline void inc_rfc1001_len(void *pSMB, int count)
+inline void inc_rfc1001_len(void *pSMB, int count)
{
struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
@@ -2001,7 +2001,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
}
do {
- rc = cifs_async_writev(wdata);
+ rc = wdata->requeue_writev(wdata);
} while (rc == -EAGAIN);
for (i = 0; i < wdata->nr_pages; i++) {
@@ -2108,6 +2108,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
break;
}
+ wdata->requeue_writev = cifs_async_writev;
queue_work(system_nrt_wq, &wdata->work);
DeleteMidQEntry(mid);
atomic_dec(&tcon->ses->server->inFlight);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4e9616d..91a3edd 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1722,8 +1722,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
return rc;
}
-int cifs_writepages(struct address_space *mapping,
- struct writeback_control *wbc)
+int
+cifs_writepages_generic(struct address_space *mapping,
+ struct writeback_control *wbc,
+ awritev_callback_t *async_writev)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb);
bool done = false, scanned = false, range_whole = false;
@@ -1876,7 +1878,7 @@ retry:
rc = -EBADF;
break;
}
- rc = cifs_async_writev(wdata);
+ rc = async_writev(wdata);
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
for (i = 0; i < nr_pages; ++i)
@@ -1921,6 +1923,12 @@ retry:
return rc;
}
+int
+cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
+{
+ return cifs_writepages_generic(mapping, wbc, cifs_async_writev);
+}
+
static int
cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
{
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 40f05e4..33c0928 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -152,7 +152,7 @@ const struct address_space_operations smb2_addr_ops = {
.readpage = cifs_readpage,
/*.readpages = cifs_readpages,*/
.writepage = cifs_writepage,
- /*.writepages = cifs_writepages,*/
+ .writepages = smb2_writepages,
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
@@ -169,7 +169,7 @@ const struct address_space_operations smb2_addr_ops = {
const struct address_space_operations smb2_addr_ops_smallbuf = {
.readpage = cifs_readpage,
.writepage = cifs_writepage,
- /*.writepages = cifs_writepages,*/
+ .writepages = smb2_writepages,
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
@@ -459,3 +459,9 @@ smb2_write_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
return SMB2_write(xid, parms, written, iov, nr_segs,
remaining_bytes, timeout);
}
+
+int
+smb2_writepages(struct address_space *mapping, struct writeback_control *wbc)
+{
+ return cifs_writepages_generic(mapping, wbc, smb2_async_writev);
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 8d13b34..cc4ed73 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/vfs.h>
#include <linux/uaccess.h>
+#include <linux/pagemap.h>
#include <linux/xattr.h>
#include "smb2pdu.h"
#include "cifsglob.h"
@@ -2432,6 +2433,127 @@ int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
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 write_rsp *smb2 = (struct write_rsp *)mid->resp_buf;
+ unsigned int credits_received = 1;
+
+ switch (mid->mid_state) {
+ case MID_RESPONSE_RECEIVED:
+ credits_received = le16_to_cpu(smb2->hdr.CreditRequest);
+ wdata->result = smb2_check_receive(mid, tcon->ses->server,
+ get_rfc1002_length(smb2), 0);
+ if (wdata->result != 0)
+ break;
+
+ written = le32_to_cpu(smb2->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;
+ }
+
+ wdata->requeue_writev = smb2_async_writev;
+ queue_work(system_nrt_wq, &wdata->work);
+ smb2_mid_entry_free(mid);
+ atomic_add(credits_received, &tcon->ses->server->credits);
+ wake_up(&tcon->ses->server->request_q);
+}
+
+/* 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 write_req *smb2 = NULL;
+ struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+ struct inode *inode = wdata->cfile->dentry->d_inode;
+ struct kvec *iov = NULL;
+
+ rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &smb2);
+ 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;
+ }
+
+ smb2->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+
+ smb2->PersistentFileId = wdata->cfile->persist_fid;
+ smb2->VolatileFileId = wdata->cfile->volatile_fid;
+ smb2->WriteChannelInfoOffset = 0;
+ smb2->WriteChannelInfoLength = 0;
+ smb2->Channel = 0;
+ smb2->Offset = cpu_to_le64(wdata->offset);
+ smb2->DataOffset = cpu_to_le16(offsetof(struct write_req, Buffer) - 4);
+ smb2->RemainingBytes = 0;
+
+ /* 4 for RFC1001 length + 1 for BCC */
+ iov[0].iov_len = be32_to_cpu(smb2->hdr.smb2_buf_length) + 4 - 1;
+ iov[0].iov_base = smb2;
+
+ /* marshal up the pages into iov array */
+ wdata->bytes = 0;
+ for (i = 0; i < wdata->nr_pages; i++) {
+ iov[i + 1].iov_len = min(inode->i_size -
+ page_offset(wdata->pages[i]),
+ (loff_t)PAGE_CACHE_SIZE);
+ iov[i + 1].iov_base = kmap(wdata->pages[i]);
+ wdata->bytes += iov[i + 1].iov_len;
+ }
+
+ cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+ smb2->Length = cpu_to_le32(wdata->bytes);
+
+ inc_rfc1001_len(&smb2->hdr, wdata->bytes - 1);
+
+ kref_get(&wdata->refcount);
+ rc = smb2_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
+ NULL, smb2_writev_callback, wdata, false);
+
+ 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(smb2);
+ kfree(iov);
+ return rc;
+}
+
int SMB2_lock(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
u64 length, u64 offset, u32 lockFlags, int wait)
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 7798626..d017843 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -22,6 +22,7 @@
#define _SMB2PROTO_H
#include <linux/nls.h>
#include <linux/key-type.h>
+#include "cifsproto.h"
struct statfs;
@@ -66,12 +67,20 @@ extern int map_smb2_to_linux_error(struct smb2_hdr *smb2, int logErr);
extern __le16 *cifs_convert_path_to_ucs(const char *from,
struct nls_table *local_nls);
+extern int smb2_check_receive(struct mid_q_entry *mid,
+ struct TCP_Server_Info *server,
+ unsigned int receive_len, bool log_error);
+extern void smb2_mid_entry_free(struct mid_q_entry *mid_entry);
extern int smb2_send(struct TCP_Server_Info *, struct smb2_hdr *,
unsigned int /* length */);
extern int smb2_sendrcv2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec *, int /* nvec to send */,
int * /* type of buf returned */,
int * /* smb2 network status code */, const int flags);
+extern int smb2_call_async(struct TCP_Server_Info *server, struct kvec *iov,
+ unsigned int nvec, mid_receive_t *receive,
+ mid_callback_t *callback, void *cbdata,
+ bool ignore_pend);
extern int smb2_send_complex(const unsigned int, struct cifs_ses *,
struct kvec *, int /* nvec to send */,
int * /* type of buf returned */,
@@ -133,6 +142,8 @@ extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
+extern int smb2_writepages(struct address_space *mapping,
+ struct writeback_control *wbc);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
@@ -200,6 +211,7 @@ extern int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
extern int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec,
const unsigned int remaining_bytes, int wtimeout);
+extern int smb2_async_writev(struct cifs_writedata *wdata);
extern int SMB2_write_complex(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
const unsigned int count, const __u64 lseek,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 68cbba9..adb701f 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -168,7 +168,7 @@ static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf,
return 0;
}
-static void
+void
smb2_mid_entry_free(struct mid_q_entry *mid_entry)
{
#ifdef CONFIG_CIFS_STATS2
@@ -273,7 +273,7 @@ free_smb2_mid(struct mid_q_entry *mid)
smb2_mid_entry_free(mid);
}
-static int
+int
smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
unsigned int receive_len, bool log_error)
{
@@ -444,4 +444,67 @@ out:
wake_up(&ses->server->request_q);
return rc;
}
+
+/*
+ * Send a SMB2 request and set the callback function in the mid to handle
+ * the result. Caller is responsible for dealing with timeouts.
+ */
+int
+smb2_call_async(struct TCP_Server_Info *server, struct kvec *iov,
+ unsigned int nvec, mid_receive_t *receive,
+ mid_callback_t *callback, void *cbdata, bool ignore_pend)
+{
+ int rc;
+ struct mid_q_entry *mid;
+ struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
+
+ rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
+ if (rc)
+ return rc;
+
+ mutex_lock(&server->srv_mutex);
+
+ smb2_seq_num_into_buf(server, iov);
+
+ mid = smb2_mid_entry_alloc(hdr, server);
+ if (mid == NULL) {
+ mutex_unlock(&server->srv_mutex);
+ atomic_inc(&server->credits);
+ wake_up(&server->request_q);
+ return -ENOMEM;
+ }
+
+ /* put it on the pending_mid_q */
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&mid->qhead, &server->pending_mid_q);
+ spin_unlock(&GlobalMid_Lock);
+
+/* rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
+ if (rc) {
+ mutex_unlock(&server->srv_mutex);
+ goto out_err;
+ }
+*/
+
+ mid->receive = receive;
+ mid->callback = callback;
+ mid->callback_data = cbdata;
+ mid->mid_state = MID_REQUEST_SUBMITTED;
+
+ cifs_in_send_inc(server);
+ rc = smb_sendv(server, iov, nvec);
+ cifs_in_send_dec(server);
+ cifs_save_when_sent(mid);
+ mutex_unlock(&server->srv_mutex);
+
+ if (rc)
+ goto out_err;
+
+ return rc;
+out_err:
+ free_smb2_mid(mid);
+ atomic_inc(&server->credits);
+ wake_up(&server->request_q);
+ return rc;
+}
/* BB add missing functions here */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 32/53] CIFS: Add readpages support for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (15 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 31/53] CIFS: Add writepages support " Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 33/53] CIFS: Add echo request " Pavel Shilovsky
` (6 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 16 ++++++++++
fs/cifs/cifsproto.h | 20 ++++---------
fs/cifs/cifssmb.c | 78 +++++++++++++++++++++++++++++++++++++++++----------
fs/cifs/file.c | 14 +++++++--
fs/cifs/smb2file.c | 10 ++++++-
fs/cifs/smb2pdu.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 3 ++
7 files changed, 180 insertions(+), 33 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 54125cc..bde6241 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -600,6 +600,22 @@ typedef int (reopen_callback_t)(struct cifsFileInfo *cifs_file, int xid,
struct cifs_tcon *tcon, const char *full_path,
__u32 *oplock);
+/* asynchronous read support */
+struct cifs_readdata {
+ 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;
+ unsigned int nr_iov;
+ struct kvec iov[1];
+};
+
+typedef int (areadv_callback_t)(struct cifs_readdata *);
+
struct cifs_writedata;
typedef int (awritev_callback_t)(struct cifs_writedata *);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6cf4313..e540117 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -205,6 +205,11 @@ extern int cifs_launder_page(struct page *page);
extern int cifs_readpage(struct file *file, struct page *page);
extern int cifs_readpages(struct file *file, struct address_space *mapping,
struct list_head *page_list, unsigned num_pages);
+extern int cifs_readpages_generic(struct file *file,
+ struct address_space *mapping,
+ struct list_head *page_list,
+ unsigned num_pages,
+ areadv_callback_t *read_cb);
extern int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc);
extern int cifs_writepages_generic(struct address_space *mapping,
@@ -495,23 +500,10 @@ 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 cifsFileInfo *cfile;
- struct address_space *mapping;
- __u64 offset;
- unsigned int bytes;
- pid_t pid;
- int result;
- struct list_head pages;
- struct work_struct work;
- unsigned int nr_iov;
- struct kvec iov[1];
-};
-
struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages);
void cifs_readdata_free(struct cifs_readdata *rdata);
int cifs_async_readv(struct cifs_readdata *rdata);
+int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
int cifs_async_writev(struct cifs_writedata *wdata);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 0c73678..5c81cd4 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -43,6 +43,9 @@
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "fscache.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
#ifdef CONFIG_CIFS_POSIX
static struct {
@@ -1410,17 +1413,24 @@ cifs_readdata_free(struct cifs_readdata *rdata)
static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
- READ_RSP *rsp = (READ_RSP *)server->smallbuf;
- unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
+ unsigned int rfclen = get_rfc1002_length(server->smallbuf);
int remaining = rfclen + 4 - server->total_read;
struct cifs_readdata *rdata = mid->callback_data;
+ size_t max_hdr_size;
+
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ max_hdr_size = MAX_SMB2_HDR_SIZE;
+ else
+#endif
+ max_hdr_size = MAX_CIFS_HDR_SIZE;
while (remaining > 0) {
int length;
length = cifs_read_from_socket(server, server->bigbuf,
min_t(unsigned int, remaining,
- CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
+ CIFSMaxBufSize + max_hdr_size));
if (length < 0)
return length;
server->total_read += length;
@@ -1431,30 +1441,47 @@ 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;
unsigned int data_offset, remaining, data_len;
struct cifs_readdata *rdata = mid->callback_data;
- READ_RSP *rsp = (READ_RSP *)server->smallbuf;
- unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
+ unsigned int rfclen = get_rfc1002_length(server->smallbuf) + 4;
+ READ_RSP *smb_rsp = NULL;
+#ifdef CONFIG_CIFS_SMB2
+ struct read_rsp *smb2_rsp = NULL;
+#endif
u64 eof;
pgoff_t eof_index;
struct page *page, *tpage;
+ size_t read_buf_size, buf_size;
cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
mid->mid, rdata->offset, rdata->bytes);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2) {
+ smb2_rsp = (struct read_rsp *)server->smallbuf;
+ read_buf_size = sizeof(*smb2_rsp) - 1;
+ buf_size = sizeof(struct smb2_hdr);
+ } else {
+#endif
+ smb_rsp = (READ_RSP *)server->smallbuf;
+ read_buf_size = sizeof(*smb_rsp);
+ buf_size = sizeof(struct smb_hdr);
+#ifdef CONFIG_CIFS_SMB2
+ }
+#endif
+
/*
* read the rest of READ_RSP header (sans Data array), or whatever we
* can if there's not enough data. At this point, we've read down to
* the Mid.
*/
- len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
- sizeof(struct smb_hdr) + 1;
+ len = min_t(unsigned int, rfclen, read_buf_size) - buf_size + 1;
- rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
+ rdata->iov[0].iov_base = server->smallbuf + buf_size - 1;
rdata->iov[0].iov_len = len;
length = cifs_readv_from_socket(server, rdata->iov, 1, len);
@@ -1463,7 +1490,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
server->total_read += length;
/* Was the SMB read successful? */
- rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ rdata->result = map_smb2_to_linux_error(&smb2_rsp->hdr, false);
+ else
+#endif
+ rdata->result = map_smb_to_linux_error(&smb_rsp->hdr, false);
if (rdata->result != 0) {
cFYI(1, "%s: server returned error %d", __func__,
rdata->result);
@@ -1471,14 +1503,20 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
}
/* Is there enough to get to the rest of the READ_RSP header? */
- if (server->total_read < sizeof(READ_RSP)) {
+ if (server->total_read < read_buf_size) {
cFYI(1, "%s: server returned short header. got=%u expected=%zu",
- __func__, server->total_read, sizeof(READ_RSP));
+ __func__, server->total_read, read_buf_size);
rdata->result = -EIO;
return cifs_readv_discard(server, mid);
}
- data_offset = le16_to_cpu(rsp->DataOffset) + 4;
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ data_offset = smb2_rsp->DataOffset;
+ else
+#endif
+ data_offset = le16_to_cpu(smb_rsp->DataOffset);
+ data_offset += 4;
if (data_offset < server->total_read) {
/*
* win2k8 sometimes sends an offset of 0 when the read
@@ -1517,8 +1555,16 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
/* how much data is in the response? */
- data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
- data_len += le16_to_cpu(rsp->DataLength);
+#ifdef CONFIG_CIFS_SMB2
+ if (server->is_smb2)
+ data_len = le32_to_cpu(smb2_rsp->DataLength);
+ else {
+#endif
+ data_len = le16_to_cpu(smb_rsp->DataLengthHigh) << 16;
+ data_len += le16_to_cpu(smb_rsp->DataLength);
+#ifdef CONFIG_CIFS_SMB2
+ }
+#endif
if (data_offset + data_len > rfclen) {
/* data_len is corrupt -- discard frame */
rdata->result = -EIO;
@@ -1605,6 +1651,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (server->total_read < rfclen)
return cifs_readv_discard(server, mid);
+ mid->resp_buf = server->smallbuf;
+ server->smallbuf = NULL;
dequeue_mid(mid, false);
return length;
}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 91a3edd..d090b6b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2686,8 +2686,9 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
return rc;
}
-int cifs_readpages(struct file *file, struct address_space *mapping,
- struct list_head *page_list, unsigned num_pages)
+int cifs_readpages_generic(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages,
+ areadv_callback_t *async_readv)
{
int rc;
struct list_head tmplist;
@@ -2817,7 +2818,7 @@ int cifs_readpages(struct file *file, struct address_space *mapping,
if (rc != 0)
continue;
}
- rc = cifs_async_readv(rdata);
+ rc = async_readv(rdata);
} while (rc == -EAGAIN);
if (rc != 0) {
@@ -2836,6 +2837,13 @@ int cifs_readpages(struct file *file, struct address_space *mapping,
return rc;
}
+int cifs_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages)
+{
+ return cifs_readpages_generic(file, mapping, page_list, num_pages,
+ cifs_async_readv);
+}
+
static int cifs_readpage_worker(struct file *file, struct page *page,
loff_t *poffset)
{
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 33c0928..48e2a36 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -150,7 +150,7 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
const struct address_space_operations smb2_addr_ops = {
.readpage = cifs_readpage,
- /*.readpages = cifs_readpages,*/
+ .readpages = smb2_readpages,
.writepage = cifs_writepage,
.writepages = smb2_writepages,
.write_begin = cifs_write_begin,
@@ -465,3 +465,11 @@ smb2_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
return cifs_writepages_generic(mapping, wbc, smb2_async_writev);
}
+
+int
+smb2_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages)
+{
+ return cifs_readpages_generic(file, mapping, page_list, num_pages,
+ smb2_async_readv);
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index cc4ed73..8e1a51c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -29,6 +29,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/pagemap.h>
#include <linux/xattr.h>
@@ -2370,6 +2371,77 @@ int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
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 *)mid->resp_buf;
+ 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;
+ }
+
+ queue_work(system_nrt_wq, &rdata->work);
+ smb2_mid_entry_free(mid);
+ atomic_add(credits_received, &server->credits);
+ wake_up(&server->request_q);
+}
+
+/* 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.volatile_fid = rdata->cfile->volatile_fid;
+ io_parms.persist_fid = rdata->cfile->persist_fid;
+ io_parms.pid = rdata->pid;
+ rc = new_read_req(&rdata->iov[0], &io_parms, 0, 0);
+ if (rc)
+ return rc;
+
+ buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+ rdata->iov[0].iov_len = get_rfc1002_length(rdata->iov[0].iov_base) + 4;
+
+ rc = smb2_call_async(io_parms.tcon->ses->server, rdata->iov, 1,
+ cifs_readv_receive, smb2_readv_callback,
+ rdata, false);
+
+ cifs_small_buf_release(buf);
+ 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
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index d017843..5ae8beb 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -144,6 +144,8 @@ extern ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern int smb2_writepages(struct address_space *mapping,
struct writeback_control *wbc);
+extern int smb2_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
@@ -208,6 +210,7 @@ extern int SMB2_close(const int xid, struct cifs_tcon *tcon,
extern int SMB2_read(const int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, char **buf, int *pbuf_type,
unsigned int remaining_bytes);
+extern int smb2_async_readv(struct cifs_readdata *rdata);
extern int SMB2_write(const int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec,
const unsigned int remaining_bytes, int wtimeout);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 33/53] CIFS: Add echo request support for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (16 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 32/53] CIFS: Add readpages " Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (5 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 3 ++
fs/cifs/connect.c | 18 ++++------
fs/cifs/smb2pdu.c | 89 +++++++++++++++++++--------------------------------
fs/cifs/smb2proto.h | 3 +-
fs/cifs/smb2sess.c | 25 ++++++++++++++
5 files changed, 70 insertions(+), 68 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bde6241..d878378 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -79,6 +79,9 @@
/* (max path length + 1 for null) * 2 for unicode */
#define MAX_NAME 514
+/* SMB echo "timeout" -- FIXME: tunable? */
+#define SMB_ECHO_INTERVAL (60 * HZ)
+
#include "cifspdu.h"
#ifndef XATTR_DOS_ATTRIB
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 62edb10..d3752e0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -55,9 +55,6 @@
#define CIFS_PORT 445
#define RFC1001_PORT 139
-/* SMB echo "timeout" -- FIXME: tunable? */
-#define SMB_ECHO_INTERVAL (60 * HZ)
-
extern mempool_t *cifs_req_poolp;
/* FIXME: should these be tunable? */
@@ -316,13 +313,7 @@ cifs_echo_request(struct work_struct *work)
time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
goto requeue_echo;
- if (server->is_smb2 == false)
- rc = CIFSSMBEcho(server);
-#ifdef CONFIG_CIFS_SMB2
- else /*temporarilly disable echo requests for smb2
- rc = SMB2_echo(server); */
- rc = 0;
-#endif
+ rc = CIFSSMBEcho(server);
if (rc)
cFYI(1, "Unable to send echo request to server: %s",
server->hostname);
@@ -2025,7 +2016,12 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
tcp_ses->lstrp = jiffies;
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
- INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+ if (volume_info->use_smb2 == false)
+ INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+#ifdef CONFIG_CIFS_SMB2
+ else
+ INIT_DELAYED_WORK(&tcp_ses->echo, smb2_echo_request);
+#endif
/*
* at this point we are the only ones with the pointer
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 8e1a51c..bbf7299 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1224,73 +1224,50 @@ int SMB2_flush(const int xid, struct cifs_tcon *tcon,
/*
- * Although the tcon value is not needed to send the echo, the
- * echo is useful when problems with slow operations show up
- * on a tcon, and also after a mount to recognize very slow links
- * so it is useful to associate the results of echo with a tcon
- * and pass in a tcon to this function.
+ * 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
+ * gets updated.
+ *
+ * FIXME: maybe we should consider checking that the reply matches request?
*/
-int SMB2_echo(const int xid, struct cifs_tcon *tcon)
+static void
+smb2_echo_callback(struct mid_q_entry *mid)
{
- struct echo_req *pSMB2;
- struct TCP_Server_Info *server;
- struct cifs_ses *ses = tcon->ses;
- struct kvec iov[1];
- int resp_buftype;
- int status;
- int rc = 0;
- unsigned long when_sent;
+ struct TCP_Server_Info *server = mid->callback_data;
+ struct echo_rsp *smb2 = (struct echo_rsp *)mid->resp_buf;
+ unsigned int credits_received = 1;
- cFYI(1, "Echo");
+ if (mid->mid_state == MID_RESPONSE_RECEIVED)
+ credits_received = le16_to_cpu(smb2->hdr.CreditRequest);
- if (ses && (ses->server))
- server = ses->server;
- else
- return -EIO;
+ smb2_mid_entry_free(mid);
+ atomic_add(credits_received, &server->credits);
+ wake_up(&server->request_q);
+}
- rc = small_smb2_init(SMB2_ECHO, tcon, (void **) &pSMB2);
- if (rc)
- return rc;
+int
+SMB2_echo(struct TCP_Server_Info *server)
+{
+ struct echo_req *smb2;
+ int rc = 0;
+ struct kvec iov;
- iov[0].iov_base = (char *)pSMB2;
- iov[0].iov_len = be32_to_cpu(pSMB2->hdr.smb2_buf_length)
- + 4 /* rfc1001 len */;
+ cFYI(1, "In echo request");
- when_sent = jiffies;
- rc = smb2_sendrcv2(xid, ses, iov, 1, &resp_buftype /* ret */, &status,
- CIFS_STD_OP | CIFS_LOG_ERROR);
+ rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&smb2);
+ if (rc)
+ return rc;
- /*
- * 15 jiffies is about 60 milliseconds - and plenty of time for network
- * request to reach server and be processed but if it takes 1000 jiffies
- * (about 4 seconds) then network or server is sick. 15 seconds and it
- * would have timed out and returned an error.
- */
- if (time_before(jiffies, when_sent + 3))
- tcon->ses->server->speed = SMB2_ECHO_FAST;
- else if (time_before(jiffies, when_sent + 15))
- tcon->ses->server->speed = SMB2_ECHO_OK;
- else if (time_before(jiffies, when_sent + 125)) {
- tcon->ses->server->speed = SMB2_ECHO_SLOW;
- cERROR(1, "slow network, SMB2 echo took %lu jiffies",
- when_sent - jiffies);
- } else if (time_before(jiffies, when_sent + 1000)) {
- tcon->ses->server->speed = SMB2_ECHO_VERY_SLOW;
- cERROR(1, "bad network? SMB2 echo took %lu jiffies",
- when_sent - jiffies);
- } else {
- tcon->ses->server->speed = SMB2_ECHO_TIMEOUT;
- cERROR(1, "server may be down - echo took %lu jiffies",
- when_sent - jiffies);
- }
+ iov.iov_base = smb2;
+ iov.iov_len = be32_to_cpu(smb2->hdr.smb2_buf_length) + 4;
- cFYI(1, "ECHO speed %d rc %d status %d", tcon->ses->server->speed, rc,
- status);
+ rc = smb2_call_async(server, &iov, 1, NULL, smb2_echo_callback, server,
+ false);
+ if (rc)
+ cFYI(1, "Echo request failed: %d", rc);
- if (rc != 0)
- cifs_stats_fail_inc(tcon, SMB2ECHO);
+ cifs_small_buf_release(smb2);
- free_rsp_buf(resp_buftype, iov[0].iov_base);
return rc;
}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 5ae8beb..45ce215 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -96,6 +96,7 @@ extern int sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *);
/* BB FIXME - need to add SMB2's signing mechanism - not same as CIFS BB */
/*extern int smb2_verify_signature(struct smb2_hdr *,
const struct mac_key *mac_key);*/
+extern void smb2_echo_request(struct work_struct *work);
extern int smb2_demultiplex_thread(struct TCP_Server_Info *server);
extern int smb2_observe_thread(struct TCP_Server_Info *server);
extern int smb2_reconnect(struct TCP_Server_Info *server);
@@ -174,7 +175,7 @@ extern int SMB2_tcon(unsigned int xid, struct cifs_ses *ses,
const struct nls_table *);
extern int SMB2_tdis(const int xid, struct cifs_tcon *tcon);
extern int SMB2_logoff(const int xid, struct cifs_ses *ses);
-extern int SMB2_echo(const int xid, struct cifs_tcon *tcon);
+extern int SMB2_echo(struct TCP_Server_Info *server);
extern int SMB2_QFS_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
struct kstatfs *FSData);
diff --git a/fs/cifs/smb2sess.c b/fs/cifs/smb2sess.c
index 5e51eb4..2a63937 100644
--- a/fs/cifs/smb2sess.c
+++ b/fs/cifs/smb2sess.c
@@ -82,3 +82,28 @@ int smb2_setup_session(unsigned int xid, struct cifs_ses *psesinfo,
ss_err_exit:
return rc;
}
+
+void
+smb2_echo_request(struct work_struct *work)
+{
+ int rc = 0;
+ struct TCP_Server_Info *server = container_of(work,
+ struct TCP_Server_Info, echo.work);
+
+ /*
+ * We cannot send an echo until the NEGOTIATE_PROTOCOL request is
+ * done, which is indicated by max_read != 0. Also, no need to ping
+ * if we got a response recently.
+ */
+ if (server->max_read == 0 ||
+ time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
+ goto requeue_echo;
+
+ rc = SMB2_echo(server);
+ if (rc)
+ cFYI(1, "Unable to send echo request to server: %s",
+ server->hostname);
+
+requeue_echo:
+ queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 34/53] [CIFS] Add SMB2 support for cifs_get_file_info
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (12 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 29/53] CIFS: Respect max buf size for SMB2 read and write Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 35/53] CIFS: Add SMB2 support for create operation Pavel Shilovsky
` (13 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/inode.c | 18 +++++++++++++++---
fs/cifs/smb2inode.c | 42 ++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 1 +
3 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a465d04..9db398e 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -568,7 +568,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_query_file_info(struct file *filp)
{
int rc;
int xid;
@@ -599,7 +600,7 @@ int cifs_get_file_info(struct file *filp)
rc = 0;
CIFS_I(inode)->time = 0;
default:
- goto cgfi_exit;
+ goto cqfi_exit;
}
/*
@@ -609,11 +610,22 @@ int cifs_get_file_info(struct file *filp)
fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
cifs_fattr_to_inode(inode, &fattr);
-cgfi_exit:
+cqfi_exit:
FreeXid(xid);
return rc;
}
+int cifs_get_file_info(struct file *filp)
+{
+#ifdef CONFIG_CIFS_SMB2
+ struct cifsFileInfo *cfile = filp->private_data;
+
+ if (tlink_tcon(cfile->tlink)->ses->server->is_smb2)
+ return smb2_query_file_info(filp);
+#endif
+ return cifs_query_file_info(filp);
+}
+
static int
cifs_query_inode_info(struct inode **pinode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb, int xid,
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1d21185..17297e4 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -284,6 +284,48 @@ sqii_exit:
return rc;
}
+int smb2_query_file_info(struct file *filp)
+{
+ int rc;
+ int xid;
+ FILE_ALL_INFO find_data;
+ struct cifs_fattr fattr;
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifsFileInfo *cfile = filp->private_data;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ FILE_ALL_INFO_SMB2 *smb2_data;
+
+ smb2_data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2,
+ GFP_KERNEL);
+ if (smb2_data == NULL)
+ return -ENOMEM;
+
+ xid = GetXid();
+ rc = SMB2_query_info(xid, tcon, cfile->persist_fid,
+ cfile->volatile_fid, smb2_data);
+ if (!rc) {
+ move_smb2_info_to_cifs(&find_data, smb2_data);
+ cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
+ } else if (rc == -EREMOTE) {
+ cifs_create_dfs_fattr(&fattr, inode->i_sb);
+ rc = 0;
+ } else
+ goto sqfi_exit;
+
+ /*
+ * don't bother with SFU junk here -- just mark inode as needing
+ * revalidation.
+ */
+ fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
+ fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
+ cifs_fattr_to_inode(inode, &fattr);
+sqfi_exit:
+ FreeXid(xid);
+ kfree(smb2_data);
+ return rc;
+}
+
int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode)
{
int rc = 0, tmprc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 45ce215..73bc050 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -105,6 +105,7 @@ extern int smb2_setup_session(unsigned int xid, struct cifs_ses *pses_info,
extern int smb2_umount(struct super_block *, struct cifs_sb_info *);
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, FILE_ALL_INFO_SMB2 *src);
+extern int smb2_query_file_info(struct file *filp);
extern int smb2_query_inode_info(struct inode **pinode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 35/53] CIFS: Add SMB2 support for create operation
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (13 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 34/53] [CIFS] Add SMB2 support for cifs_get_file_info Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 36/53] CIFS: Add readdir support for SMB2 Pavel Shilovsky
` (12 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2proto.h | 2 +
2 files changed, 187 insertions(+), 1 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 17297e4..ff9d174 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -23,6 +23,8 @@
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
+#include <linux/namei.h>
+#include <linux/file.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
@@ -36,7 +38,7 @@
#include "smb2proto.h"
const struct inode_operations smb2_dir_inode_ops = {
- .create = cifs_create,
+ .create = smb2_create,
.lookup = cifs_lookup,
.getattr = cifs_getattr,
.unlink = smb2_unlink,
@@ -568,3 +570,185 @@ unlink_out:
cifs_put_tlink(tlink);
return rc;
}
+
+static int
+smb2_create_helper(struct inode *dir, struct dentry *direntry, int mode,
+ struct nameidata *nd, __u32 *oplock, __u64 *persist_fid,
+ __u64 *volatile_fid, int xid, struct cifs_tcon *tcon,
+ const char *full_path, void *data)
+{
+ int rc;
+ __u32 desired_access;
+ __u32 create_disposition;
+ __u32 create_options = CREATE_NOT_DIR;
+ __u32 oflags;
+ __le16 *smb2_path;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir->i_sb);
+ FILE_ALL_INFO_SMB2 *smb2_data = NULL;
+
+ if (nd) {
+ /* if the file is going to stay open, then we
+ need to set the desired access properly */
+ oflags = nd->intent.open.file->f_flags;
+
+ /* read attributes access to get attributes of inode */
+ desired_access = FILE_READ_ATTRIBUTES;
+ if (OPEN_FMODE(oflags) & FMODE_READ)
+ /* is this too little?*/
+ desired_access |= GENERIC_READ;
+ if (OPEN_FMODE(oflags) & FMODE_WRITE)
+ desired_access |= GENERIC_WRITE;
+
+ if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ create_disposition = FILE_CREATE;
+ else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+ create_disposition = FILE_OVERWRITE_IF;
+ else if ((oflags & O_CREAT) == O_CREAT)
+ create_disposition = FILE_OPEN_IF;
+ else {
+ create_disposition = FILE_OPEN;
+ cFYI(1, "Create flag not set in create function");
+ }
+ } else {
+ desired_access = GENERIC_READ | GENERIC_WRITE;
+ create_disposition = FILE_OVERWRITE_IF;
+ }
+ /* BB pass O_SYNC flag through on file attributes .. BB */
+
+ smb2_path = cifs_convert_path_to_ucs(full_path, cifs_sb->local_nls);
+ if (smb2_path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
+ desired_access, create_disposition, 0, create_options);
+ if (rc)
+ goto out;
+
+ smb2_data = kzalloc(sizeof(FILE_ALL_INFO_SMB2) + MAX_NAME*2,
+ GFP_KERNEL);
+ if (smb2_data == NULL) {
+ rc = -ENOMEM;
+ SMB2_close(xid, tcon, *persist_fid, *volatile_fid);
+ goto out;
+ }
+
+ rc = SMB2_query_info(xid, tcon, *persist_fid, *volatile_fid, smb2_data);
+ if (rc) {
+ SMB2_close(xid, tcon, *persist_fid, *volatile_fid);
+ goto out;
+ }
+
+ move_smb2_info_to_cifs(data, smb2_data);
+
+out:
+ *oplock = 0;
+ kfree(smb2_data);
+ kfree(smb2_path);
+ return rc;
+}
+
+int
+smb2_create(struct inode *dir, struct dentry *direntry, int mode,
+ struct nameidata *nd)
+{
+ int rc = -ENOENT;
+ int xid;
+ __u32 oplock = 0;
+ /*
+ * BB below access is probably too much for mknod to request
+ * but we have to do query and setpathinfo so requesting
+ * less could fail (unless we want to request getatr and setatr
+ * permissions (only). At least for POSIX we do not have to
+ * request so much.
+ */
+ __u64 persist_fid, volatile_fid;
+ struct cifs_sb_info *cifs_sb;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct inode *newinode = NULL;
+ FILE_ALL_INFO *buf;
+ char *full_path;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(dir->i_sb);
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink)) {
+ FreeXid(xid);
+ return PTR_ERR(tlink);
+ }
+ tcon = tlink_tcon(tlink);
+
+ if (oplockEnabled)
+ oplock = REQ_OPLOCK;
+
+ buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ full_path = build_path_from_dentry(direntry);
+ if (full_path == NULL) {
+ rc = -ENOMEM;
+ goto smb2_create_out;
+ }
+
+ rc = smb2_create_helper(dir, direntry, mode, nd, &oplock, &persist_fid,
+ &volatile_fid, xid, tcon, full_path, buf);
+ if (rc) {
+ cFYI(1, "smb2_create returned 0x%x", rc);
+ goto smb2_create_out;
+ }
+
+ rc = smb2_query_inode_info(&newinode, full_path, buf, dir->i_sb, xid);
+ if (rc) {
+ cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ goto smb2_create_out;
+ }
+
+ if (newinode) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ newinode->i_mode = mode;
+ if ((oplock & CIFS_CREATE_ACTION) &&
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
+ newinode->i_uid = current_fsuid();
+ if (dir->i_mode & S_ISGID)
+ newinode->i_gid = dir->i_gid;
+ else
+ newinode->i_gid = current_fsgid();
+ }
+ }
+
+ d_instantiate(direntry, newinode);
+
+ if (newinode && nd) {
+ struct cifsFileInfo *file_info;
+ struct file *filp;
+
+ filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
+ if (IS_ERR(filp)) {
+ rc = PTR_ERR(filp);
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ goto smb2_create_out;
+ }
+
+ file_info = smb2_new_fileinfo(persist_fid, volatile_fid,
+ filp, tlink, oplock);
+ if (file_info == NULL) {
+ fput(filp);
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ rc = -ENOMEM;
+ }
+ } else {
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ }
+
+smb2_create_out:
+ kfree(buf);
+ kfree(full_path);
+ cifs_put_tlink(tlink);
+ FreeXid(xid);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 73bc050..5782a10 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -149,6 +149,8 @@ extern int smb2_writepages(struct address_space *mapping,
extern int smb2_readpages(struct file *file, struct address_space *mapping,
struct list_head *page_list, unsigned num_pages);
+extern int smb2_create(struct inode *dir, struct dentry *direntry, int mode,
+ struct nameidata *nd);
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 36/53] CIFS: Add readdir support for SMB2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (14 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 35/53] CIFS: Add SMB2 support for create operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 37/53] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
` (11 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsproto.h | 4 +
fs/cifs/file.c | 68 ++++---
fs/cifs/readdir.c | 4 +-
fs/cifs/smb2dir.c | 2 +-
fs/cifs/smb2glob.h | 1 -
fs/cifs/smb2pdu.c | 20 +-
fs/cifs/smb2proto.h | 7 +-
fs/cifs/smb2readdir.c | 591 +++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 651 insertions(+), 46 deletions(-)
create mode 100644 fs/cifs/smb2readdir.c
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e540117..4285c10 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -216,6 +216,10 @@ extern int cifs_writepages_generic(struct address_space *mapping,
struct writeback_control *wbc,
awritev_callback_t *async_writev);
extern int cifs_writepage(struct page *page, struct writeback_control *wbc);
+extern int is_dir_changed(struct file *file);
+extern struct dentry *cifs_readdir_lookup(struct dentry *parent,
+ struct qstr *name,
+ struct cifs_fattr *fattr);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index d090b6b..22cf18b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -658,47 +658,55 @@ int cifs_closedir(struct inode *inode, struct file *file)
{
int rc = 0;
int xid;
- struct cifsFileInfo *pCFileStruct = file->private_data;
- char *ptmp;
+ struct cifsFileInfo *cfile = file->private_data;
+ struct cifs_tcon *tcon;
+ char *buf;
cFYI(1, "Closedir inode = 0x%p", inode);
+ if (cfile == NULL)
+ return rc;
+
xid = GetXid();
+ tcon = tlink_tcon(cfile->tlink);
- if (pCFileStruct) {
- struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->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);
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2)
+ rc = SMB2_close(xid, tcon, cfile->persist_fid,
+ cfile->volatile_fid);
+ else
+#endif
+ rc = CIFSFindClose(xid, tcon, cfile->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);
- cFYI(1, "Freeing private data in close dir");
- spin_lock(&cifs_file_list_lock);
- if (!pCFileStruct->srch_inf.endOfSearch &&
- !pCFileStruct->invalidHandle) {
- pCFileStruct->invalidHandle = true;
- spin_unlock(&cifs_file_list_lock);
- rc = CIFSFindClose(xid, pTcon, pCFileStruct->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) {
- 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);
- else
- cifs_buf_release(ptmp);
- }
- cifs_put_tlink(pCFileStruct->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? */
FreeXid(xid);
return rc;
}
+
loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/*
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 5de03ec..fbc4374 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -69,7 +69,7 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
* Find the dentry that matches "name". If there isn't one, create one. If it's
* a negative dentry or the uniqueid changed, then drop it and recreate it.
*/
-static struct dentry *
+struct dentry *
cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
struct cifs_fattr *fattr)
{
@@ -465,7 +465,7 @@ static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
/* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */
-static int is_dir_changed(struct file *file)
+int is_dir_changed(struct file *file)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
diff --git a/fs/cifs/smb2dir.c b/fs/cifs/smb2dir.c
index 957338c..2ae2fcd 100644
--- a/fs/cifs/smb2dir.c
+++ b/fs/cifs/smb2dir.c
@@ -36,7 +36,7 @@
#include "smb2proto.h"
const struct file_operations smb2_dir_ops = {
- .readdir = cifs_readdir,
+ .readdir = smb2_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
.unlocked_ioctl = cifs_ioctl,
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 1fe5813..55d76ad 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -31,7 +31,6 @@
#define SMB2_MIN_RCV_POOL 4
-
/*
*****************************************************************
* Except the SMB2 PDUs themselves all the
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index bbf7299..e5373da 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1451,7 +1451,7 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry)
*/
int SMB2_query_directory(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int index,
- struct smb2_search *psrch_inf)
+ struct cifs_search_info *psrch_inf)
{
struct query_directory_req *pSMB2;
struct query_directory_rsp *pSMB2r = NULL;
@@ -1526,24 +1526,24 @@ int SMB2_query_directory(const int xid, struct cifs_tcon *tcon,
(char *)&pSMB2r->hdr + le16_to_cpu(pSMB2r->OutputBufferOffset);
end_of_smb = be32_to_cpu(pSMB2r->hdr.smb2_buf_length) +
4 /* RFC1001len field */ + (char *)&pSMB2r->hdr;
- psrch_inf->entries_in_buf = num_entries(psrch_inf->srch_entries_start,
- end_of_smb,
- &psrch_inf->last_entry);
- psrch_inf->index_of_last_entry += psrch_inf->entries_in_buf;
+ psrch_inf->entries_in_buffer =
+ num_entries(psrch_inf->srch_entries_start, end_of_smb,
+ &psrch_inf->last_entry);
+ psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer;
cFYI(1, "num entries %d last_index %lld srch start %p srch end %p",
- psrch_inf->entries_in_buf, psrch_inf->index_of_last_entry,
+ psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry,
psrch_inf->srch_entries_start, psrch_inf->last_entry);
if (resp_buftype == CIFS_LARGE_BUFFER)
- psrch_inf->small_buf = false;
+ psrch_inf->smallBuf = false;
else if (resp_buftype == CIFS_SMALL_BUFFER)
- psrch_inf->small_buf = true;
+ psrch_inf->smallBuf = true;
else
cERROR(1, "illegal search buffer type");
if (le32_to_cpu(pSMB2r->hdr.Status) == STATUS_NO_MORE_FILES)
- psrch_inf->search_end = 1;
+ psrch_inf->endOfSearch = 1;
else
- psrch_inf->search_end = 0;
+ psrch_inf->endOfSearch = 0;
return rc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 5782a10..edc8c3b 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -155,6 +155,8 @@ extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
+extern int smb2_readdir(struct file *file, void *direntry, filldir_t filldir);
+
/* extern char *smb2_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
@@ -192,8 +194,9 @@ extern int SMB2_oplock_break(struct cifs_tcon *ptcon, __u64 netfid);
extern int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
FILE_ALL_INFO_SMB2 *pFindData);
-int SMB2_query_directory(const int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, int index, struct smb2_search *);
+extern int SMB2_query_directory(const int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ int index, struct cifs_search_info *);
extern int SMB2_set_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
FILE_BASIC_INFO *pFindData);
diff --git a/fs/cifs/smb2readdir.c b/fs/cifs/smb2readdir.c
new file mode 100644
index 0000000..9598cf8
--- /dev/null
+++ b/fs/cifs/smb2readdir.c
@@ -0,0 +1,591 @@
+/*
+ * fs/cifs/smb2readdir.c
+ *
+ * Directory search handling
+ *
+ * Copyright (C) International Business Machines Corp., 2004, 2010
+ * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
+ *
+ * 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/pagemap.h>
+#include <linux/stat.h>
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "cifsfs.h"
+#include "smb2glob.h"
+#include "smb2pdu.h"
+#include "smb2proto.h"
+
+/*
+ * To be safe - for UCS to UTF-8 with strings loaded with the rare long
+ * characters alloc more to account for such multibyte target UTF-8
+ * characters.
+ */
+#define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
+
+#define UNICODE_DOT cpu_to_le16('.')
+
+/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
+static int smb2_entry_is_dot(char *current_entry, struct cifsFileInfo *sfile)
+{
+ int rc = 0;
+ char *filename = NULL;
+ int len = 0;
+
+ struct file_full_directory_info *pFindData =
+ (struct file_full_directory_info *)current_entry;
+ filename = &pFindData->filename[0];
+ len = le32_to_cpu(pFindData->filename_length);
+ cFYI(1, "filename len of entry %d", len);
+ if (filename) {
+ __le16 *ufilename = (__le16 *)filename;
+ if (len == 2) {
+ /* check for . */
+ if (ufilename[0] == UNICODE_DOT)
+ rc = 1;
+ } else if (len == 4) {
+ /* check for .. */
+ if ((ufilename[0] == UNICODE_DOT)
+ && (ufilename[1] == UNICODE_DOT))
+ rc = 2;
+ }
+ }
+
+ return rc;
+}
+
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
+{
+ char *new_entry;
+ struct file_full_directory_info *pDirInfo =
+ (struct file_full_directory_info *)old_entry;
+
+ new_entry = old_entry + le32_to_cpu(pDirInfo->next_entry_offset);
+
+ cFYI(1, "new entry %p old entry %p", new_entry, old_entry);
+ /* validate that new_entry is not past end of SMB */
+ if (new_entry >= end_of_smb) {
+ cERROR(1,
+ "search entry %p began after end of SMB %p old entry %p",
+ new_entry, end_of_smb, old_entry);
+ return NULL;
+ }
+
+ return new_entry;
+}
+
+static int smb2_save_resume_key(const char *current_entry,
+ struct cifsFileInfo *smb2file)
+{
+ int rc = 0;
+ unsigned int len = 0;
+ char *filename;
+ struct file_full_directory_info *pFindData;
+
+ if ((smb2file == NULL) || (current_entry == NULL))
+ return -EINVAL;
+
+ pFindData = (struct file_full_directory_info *)current_entry;
+
+ filename = &pFindData->filename[0];
+ len = le32_to_cpu(pFindData->filename_length);
+
+ if (len > SMB2_MAX_MSGSIZE)
+ return -EINVAL;
+
+ smb2file->srch_inf.resume_key = pFindData->file_index;
+ smb2file->srch_inf.resume_name_len = len;
+ smb2file->srch_inf.presume_name = filename;
+ return rc;
+}
+
+/* inode num, inode type and filename returned */
+static int smb2_get_name_from_search_buf(struct qstr *pqst,
+ char *current_entry,
+ struct cifs_sb_info *smb2_sb, unsigned int max_len, __u64 *pinum)
+{
+ int rc = 0;
+ unsigned int len = 0;
+ char *filename;
+ struct nls_table *nlt = smb2_sb->local_nls;
+ struct file_full_directory_info *pfinddata;
+
+ *pinum = 0;
+
+ pfinddata = (struct file_full_directory_info *)current_entry;
+
+ filename = &pfinddata->filename[0];
+ len = le32_to_cpu(pfinddata->filename_length);
+ cFYI(1, "find in search buf entry of length %d", len);
+ if (len > max_len) {
+ cERROR(1, "bad search response length %d past smb end", len);
+ return -EINVAL;
+ }
+
+ /* cifs_dump_mem("search entry filename: ", filename, len); */
+
+ pqst->len = cifs_from_ucs2((char *) pqst->name,
+ (__le16 *) filename,
+ UNICODE_NAME_MAX,
+ min(len, max_len), nlt,
+ smb2_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ pqst->hash = full_name_hash(pqst->name, pqst->len);
+ cFYI(1, "filldir on %s of len %d", pqst->name, pqst->len);
+ return rc;
+}
+
+static void
+smb2_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *smb2_sb)
+{
+ fattr->cf_uid = smb2_sb->mnt_uid;
+ fattr->cf_gid = smb2_sb->mnt_gid;
+
+ if (fattr->cf_cifsattrs & FILE_ATTRIBUTE_DIRECTORY) {
+ fattr->cf_mode = S_IFDIR | smb2_sb->mnt_dir_mode;
+ fattr->cf_dtype = DT_DIR;
+ } else {
+ fattr->cf_mode = S_IFREG | smb2_sb->mnt_file_mode;
+ fattr->cf_dtype = DT_REG;
+ }
+
+ if (fattr->cf_cifsattrs & FILE_ATTRIBUTE_READONLY)
+ fattr->cf_mode &= ~S_IWUGO;
+}
+
+static void
+smb2_dir_info_to_fattr(struct cifs_fattr *fattr,
+ struct file_full_directory_info *info,
+ struct cifs_sb_info *smb2_sb)
+{
+ memset(fattr, 0, sizeof(*fattr));
+ fattr->cf_cifsattrs = le32_to_cpu(info->file_attribute);
+ fattr->cf_eof = le64_to_cpu(info->end_of_file);
+ fattr->cf_bytes = le64_to_cpu(info->allocation_size);
+ fattr->cf_atime = cifs_NTtimeToUnix(info->last_access_time);
+ fattr->cf_ctime = cifs_NTtimeToUnix(info->change_time);
+ fattr->cf_mtime = cifs_NTtimeToUnix(info->last_write_time);
+ cFYI(1, "eof: %lld alloc_size %lld", fattr->cf_eof, fattr->cf_bytes);
+
+ smb2_fill_common_info(fattr, smb2_sb);
+}
+
+/*
+ * To be safe - for UCS to UTF-8 with strings loaded with the rare long
+ * characters alloc more to account for such multibyte target UTF-8
+ * characters.
+ */
+
+static int smb2_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
+ void *direntry, char *scratch_buf, unsigned int max_len)
+{
+ int rc = 0;
+ struct qstr qstring;
+ struct cifsFileInfo *psmb2f;
+ u64 inum;
+ ino_t ino;
+ struct super_block *sb;
+ struct cifs_sb_info *smb2_sb;
+ struct dentry *tmp_dentry;
+ struct cifs_fattr fattr;
+
+ /* get filename and len into qstring */
+ /* get dentry */
+ /* decide whether to create and populate inode */
+ if ((direntry == NULL) || (file == NULL))
+ return -EINVAL;
+
+ psmb2f = file->private_data;
+
+ if ((scratch_buf == NULL) || (pfindEntry == NULL) || (psmb2f == NULL))
+ return -ENOENT;
+
+ rc = smb2_entry_is_dot(pfindEntry, psmb2f);
+ /* skip . and .. since we added them first */
+ if (rc != 0)
+ return 0;
+
+ sb = file->f_path.dentry->d_sb;
+ smb2_sb = CIFS_SB(sb);
+
+ qstring.name = scratch_buf;
+ rc = smb2_get_name_from_search_buf(&qstring, pfindEntry,
+ smb2_sb, max_len, &inum /* returned */);
+
+ if (rc)
+ return rc;
+
+ smb2_dir_info_to_fattr(&fattr, (struct file_full_directory_info *)
+ pfindEntry, smb2_sb);
+
+ if (inum)
+ fattr.cf_uniqueid = inum;
+ else
+ fattr.cf_uniqueid = iunique(sb, ROOT_I);
+
+ ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
+ tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
+
+ rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
+ ino, fattr.cf_dtype);
+
+ /*
+ * we can not return filldir errors to the caller since they are
+ * "normal" when the stat blocksize is too small - we return remapped
+ * error instead
+ *
+ * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
+ * case already. Why should we be clobbering other errors from it?
+ */
+ if (rc) {
+ cFYI(1, "filldir rc = %d", rc);
+ rc = -EOVERFLOW;
+ }
+ dput(tmp_dentry);
+ return rc;
+}
+
+static int initiate_smb2_search(const int xid, struct file *file);
+
+/* 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_smb2_entry(const int xid, struct cifs_tcon *tcon,
+ struct file *file, char **ppcurrent_entry, int *num_to_ret)
+{
+ int rc = 0;
+ int pos_in_buf = 0;
+ loff_t first_entry_in_buffer;
+ loff_t index_to_find = file->f_pos;
+ struct cifsFileInfo *smb2file = file->private_data;
+ /* check if index in the buffer */
+
+ if ((smb2file == NULL) || (ppcurrent_entry == NULL) ||
+ (num_to_ret == NULL))
+ return -ENOENT;
+
+ *ppcurrent_entry = NULL;
+ first_entry_in_buffer =
+ smb2file->srch_inf.index_of_last_entry -
+ smb2file->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 (((index_to_find < smb2file->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_tcp_ses_lock);
+ if (!smb2file->srch_inf.endOfSearch &&
+ !smb2file->invalidHandle) {
+ smb2file->invalidHandle = true;
+ spin_unlock(&cifs_tcp_ses_lock);
+ SMB2_close(xid, tcon, smb2file->persist_fid, smb2file->volatile_fid);
+ } else
+ spin_unlock(&cifs_tcp_ses_lock);
+ if (smb2file->srch_inf.ntwrk_buf_start) {
+ cFYI(1, "freeing SMB ff cache buf on search rewind");
+ if (smb2file->srch_inf.smallBuf)
+ cifs_small_buf_release(smb2file->srch_inf.
+ ntwrk_buf_start);
+ else
+ cifs_buf_release(smb2file->srch_inf.
+ ntwrk_buf_start);
+ smb2file->srch_inf.ntwrk_buf_start = NULL;
+ }
+ rc = initiate_smb2_search(xid, file);
+ if (rc) {
+ cFYI(1, "error %d reinitiating a search on rewind",
+ rc);
+ return rc;
+ }
+ smb2_save_resume_key(smb2file->srch_inf.last_entry, smb2file);
+ }
+
+
+ while ((index_to_find >= smb2file->srch_inf.index_of_last_entry) &&
+ (rc == 0) && !smb2file->srch_inf.endOfSearch) {
+ cFYI(1, "calling findnext2");
+ rc = SMB2_query_directory(xid, tcon, smb2file->persist_fid,
+ smb2file->volatile_fid, 0,
+ &smb2file->srch_inf);
+ smb2_save_resume_key(smb2file->srch_inf.last_entry, smb2file);
+ if (rc)
+ return -ENOENT;
+ }
+ cFYI(1, "index to find %lld last %lld", index_to_find,
+ smb2file->srch_inf.index_of_last_entry);
+
+ if (index_to_find < smb2file->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 = smb2file->srch_inf.ntwrk_buf_start +
+ smb2_calc_size((struct smb2_hdr *)
+ smb2file->srch_inf.ntwrk_buf_start);
+ current_entry = smb2file->srch_inf.srch_entries_start;
+ first_entry_in_buffer = smb2file->srch_inf.index_of_last_entry
+ - smb2file->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++) {
+ /* go entry by entry figuring out which is first */
+ current_entry = nxt_dir_entry(current_entry,
+ end_of_smb);
+ }
+ if ((current_entry == 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);
+ }
+ rc = 0;
+ *ppcurrent_entry = current_entry;
+ } else {
+ cFYI(1, "index not in buffer - could not findnext into it");
+ return 0;
+ }
+
+ if (pos_in_buf >= smb2file->srch_inf.entries_in_buffer) {
+ cFYI(1, "can not return entries pos_in_buf beyond last");
+ *num_to_ret = 0;
+ } else
+ *num_to_ret = smb2file->srch_inf.entries_in_buffer - pos_in_buf;
+
+ return rc;
+}
+
+static int initiate_smb2_search(const int xid, struct file *file)
+{
+ int rc = 0;
+ __le16 *full_path;
+ struct cifsFileInfo *smb2_file;
+ struct cifs_sb_info *smb2_sb;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
+ u64 persistent_fid, volatile_fid;
+
+ smb2_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ tlink = cifs_sb_tlink(smb2_sb);
+ if (IS_ERR(tlink)) {
+ FreeXid(xid);
+ return PTR_ERR(tlink);
+ }
+ tcon = tlink_tcon(tlink);
+
+ full_path = build_ucspath_from_dentry(file->f_path.dentry);
+ if (full_path == NULL)
+ return -ENOMEM;
+
+ rc = SMB2_open(xid, tcon, full_path, &persistent_fid, &volatile_fid,
+ FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0);
+ if (rc) {
+ cERROR(1, "open of dir failed before readdir with rc = %d", rc);
+ goto initiate_search_exit;
+ }
+
+ if (file->private_data == NULL)
+ file->private_data =
+ kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+
+ if (file->private_data == NULL) {
+ rc = -ENOMEM;
+ goto initiate_search_exit;
+ }
+
+ smb2_file = file->private_data;
+ smb2_file->srch_inf.entries_in_buffer = 0;
+ smb2_file->srch_inf.index_of_last_entry = 0;
+ smb2_file->persist_fid = persistent_fid;
+ smb2_file->volatile_fid = volatile_fid;
+ smb2_file->invalidHandle = false;
+ smb2_file->tlink = cifs_get_tlink(tlink);
+ mutex_init(&smb2_file->fh_mutex);
+ INIT_WORK(&smb2_file->oplock_break, cifs_oplock_break);
+ smb2_file->count = 1;
+
+ rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid,
+ 0 /* index */, &smb2_file->srch_inf);
+ if (rc)
+ cERROR(1, "query of dir failed");
+
+ /*
+ * BB add following call to handle readdir on new NTFS symlink errors
+ if (rc == cpu_to_le32(STATUS_STOPPED_ON_SYMLINK))
+ call get_symlink_reparse_path and retry with new path
+ */
+
+initiate_search_exit:
+ kfree(full_path);
+ cifs_put_tlink(tlink);
+ return rc;
+}
+
+
+int smb2_readdir(struct file *file, void *direntry, filldir_t filldir)
+{
+ int rc = 0;
+ int xid;
+ int i;
+ struct cifs_sb_info *smb2_sb;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
+ struct cifsFileInfo *smb2_file = NULL;
+ int num_to_fill = 0;
+ char *tmp_buf = NULL;
+ char *end_of_smb;
+ unsigned int max_len;
+ char *current_entry;
+
+ xid = GetXid();
+
+ cFYI(1, "readdir on pos %d", (int) file->f_pos);
+ switch ((int) file->f_pos) {
+ case 0:
+ if (filldir(direntry, ".", 1, file->f_pos,
+ file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
+ cERROR(1, "Filldir for current dir failed");
+ rc = -ENOMEM;
+ break;
+ }
+ file->f_pos++;
+ case 1:
+ if (filldir(direntry, "..", 2, file->f_pos,
+ parent_ino(file->f_path.dentry), DT_DIR) < 0) {
+ cERROR(1, "Filldir for parent dir failed");
+ rc = -ENOMEM;
+ break;
+ }
+ file->f_pos++;
+ default:
+ /*
+ * 1) If search is active,
+ * is in current search buffer?
+ * if it before then restart search
+ * if after then keep searching till find it
+ */
+
+ if (file->private_data == NULL) {
+ rc = initiate_smb2_search(xid, file);
+ cFYI(1, "initiate smb2 search rc %d", rc);
+ if (rc)
+ goto rddir2_exit;
+ }
+ if (file->private_data == NULL) {
+ rc = -EINVAL;
+ goto rddir2_exit;
+ }
+ smb2_file = file->private_data;
+ if (smb2_file->srch_inf.endOfSearch) {
+ if (smb2_file->srch_inf.emptyDir) {
+ cFYI(1, "End of search, empty dir");
+ rc = 0;
+ break;
+ }
+ }
+
+ smb2_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ tlink = cifs_sb_tlink(smb2_sb);
+ if (IS_ERR(tlink)) {
+ FreeXid(xid);
+ return PTR_ERR(tlink);
+ }
+ tcon = tlink_tcon(tlink);
+
+ rc = find_smb2_entry(xid, tcon, file, ¤t_entry,
+ &num_to_fill);
+ cifs_put_tlink(tlink);
+
+ if (rc) {
+ cFYI(1, "find smb2 entry error %d", rc);
+ goto rddir2_exit;
+ } else if (current_entry != NULL) {
+ cFYI(1, "found entry %lld", file->f_pos);
+ } else {
+ cFYI(1, "could not find dir entry");
+ goto rddir2_exit;
+ }
+ cFYI(1, "loop through %d times filling dir with buf %p",
+ num_to_fill, smb2_file->srch_inf.ntwrk_buf_start);
+
+ max_len = smb2_calc_size((struct smb2_hdr *)
+ smb2_file->srch_inf.ntwrk_buf_start);
+ end_of_smb = smb2_file->srch_inf.ntwrk_buf_start + max_len;
+
+ tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
+ if (tmp_buf == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
+ if (current_entry == NULL) {
+ /* evaluate whether this case is an error */
+ cERROR(1, "past SMB end, num to fill %d i %d",
+ num_to_fill, i);
+ break;
+ }
+ /*
+ * if buggy server returns . and .. late do
+ * we want to check for that here?
+ */
+ rc = smb2_filldir(current_entry, file,
+ filldir, direntry, tmp_buf, max_len);
+ if (rc == -EOVERFLOW) {
+ rc = 0;
+ break;
+ }
+
+ file->f_pos++;
+ if (file->f_pos ==
+ smb2_file->srch_inf.index_of_last_entry) {
+ cFYI(1, "last entry in buf at pos %lld %s",
+ file->f_pos, tmp_buf);
+ smb2_save_resume_key(current_entry, smb2_file);
+ break;
+ } else
+ current_entry =
+ nxt_dir_entry(current_entry, end_of_smb);
+ }
+ kfree(tmp_buf);
+ break;
+ } /* end switch */
+
+rddir2_exit:
+ FreeXid(xid);
+ return rc;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 37/53] CIFS: Add SMB2 support for rename operation
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (15 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 36/53] CIFS: Add readdir support for SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 38/53] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
` (10 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2proto.h | 2 +
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index ff9d174..f881055 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -45,7 +45,7 @@ const struct inode_operations smb2_dir_inode_ops = {
.link = cifs_hardlink,
.mkdir = smb2_mkdir,
.rmdir = smb2_rmdir,
- .rename = cifs_rename,
+ .rename = smb2_rename,
.permission = cifs_permission,
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
@@ -63,7 +63,7 @@ const struct inode_operations smb2_file_inode_ops = {
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
.getattr = cifs_getattr, /* do we need this anymore? */
- .rename = cifs_rename,
+ .rename = smb2_rename,
.permission = cifs_permission,
#ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr,
@@ -167,6 +167,10 @@ smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
/* Directories are created through parameters in the
* SMB2_open() call. */
break;
+ case SMB2_OP_RENAME:
+ tmprc = SMB2_rename(xid, tcon, persist_fid, volatile_fid,
+ (__le16 *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
@@ -752,3 +756,67 @@ smb2_create_out:
FreeXid(xid);
return rc;
}
+
+static int
+smb2_do_rename(struct dentry *from_dentry, __le16 *from_path,
+ struct dentry *to_dentry, __le16 *to_path)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ int rc, xid;
+
+ xid = GetXid();
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ rc = smb2_open_op_close(xid, tcon, from_path, DELETE,
+ FILE_OPEN, 0, 0, to_path, SMB2_OP_RENAME);
+
+ cifs_put_tlink(tlink);
+ FreeXid(xid);
+ return rc;
+}
+
+int smb2_rename(struct inode *source_dir, struct dentry *source_dentry,
+ struct inode *target_dir, struct dentry *target_dentry)
+{
+ __le16 *from_name = NULL;
+ __le16 *to_name = NULL;
+ int rc, tmprc;
+
+ /*
+ * we already have the rename sem so we do not need to
+ * grab it again here to protect the path integrity
+ */
+ from_name = build_ucspath_from_dentry(source_dentry);
+ if (from_name == NULL) {
+ rc = -ENOMEM;
+ goto smb2_rename_exit;
+ }
+
+ to_name = build_ucspath_from_dentry(target_dentry);
+ if (to_name == NULL) {
+ rc = -ENOMEM;
+ goto smb2_rename_exit;
+ }
+
+ rc = smb2_do_rename(source_dentry, from_name, target_dentry, to_name);
+
+ /* Try unlinking the target dentry if it's not negative */
+ if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
+ tmprc = smb2_unlink(target_dir, target_dentry);
+ if (tmprc)
+ goto smb2_rename_exit;
+
+ rc = smb2_do_rename(source_dentry, from_name, target_dentry,
+ to_name);
+ }
+
+smb2_rename_exit:
+ kfree(from_name);
+ kfree(to_name);
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index edc8c3b..0ed7773 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -154,6 +154,8 @@ extern int smb2_create(struct inode *dir, struct dentry *direntry, int mode,
extern int smb2_mkdir(struct inode *inode, struct dentry *direntry, int mode);
extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
+extern int smb2_rename(struct inode *source_dir, struct dentry *source_dentry,
+ struct inode *target_dir, struct dentry *target_dentry);
extern int smb2_readdir(struct file *file, void *direntry, filldir_t filldir);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 38/53] CIFS: Add SMB2 support for hardlink operation
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (16 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 37/53] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 40/53] CIFS: Add NTLMSSP sec type to defaults Pavel Shilovsky
` (9 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2glob.h | 3 +-
fs/cifs/smb2inode.c | 10 +++-
fs/cifs/smb2link.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.c | 2 +-
fs/cifs/smb2proto.h | 6 +++
5 files changed, 124 insertions(+), 5 deletions(-)
create mode 100644 fs/cifs/smb2link.c
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 55d76ad..9e42f71 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -174,7 +174,7 @@ struct page_req {
#define SMB2_MAX_REQ 256
/* Identifiers for functions that use the open, operation, close pattern
- * in inode.c:open_op_close() */
+ * in smb2inode.c:smb2_open_op_close() */
#define SMB2_OP_SET_DELETE 1
#define SMB2_OP_SET_INFO 2
#define SMB2_OP_QUERY_INFO 3
@@ -182,6 +182,7 @@ struct page_req {
#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 f881055..8e69650 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -42,7 +42,7 @@ const struct inode_operations smb2_dir_inode_ops = {
.lookup = cifs_lookup,
.getattr = cifs_getattr,
.unlink = smb2_unlink,
- .link = cifs_hardlink,
+ .link = smb2_hardlink,
.mkdir = smb2_mkdir,
.rmdir = smb2_rmdir,
.rename = smb2_rename,
@@ -140,7 +140,7 @@ void smb2_set_ops(struct inode *inode)
}
}
-static int
+int
smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
__u32 desired_access, __u32 create_disposition,
__u32 file_attributes, __u32 create_options,
@@ -149,7 +149,7 @@ smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
int rc, tmprc = 0;
u64 persist_fid, volatile_fid;
- rc = SMB2_open(xid, tcon, srch_path, &persist_fid, &volatile_fid,
+ rc = SMB2_open(xid, tcon, path, &persist_fid, &volatile_fid,
desired_access, create_disposition, file_attributes,
create_options);
if (rc)
@@ -171,6 +171,10 @@ smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
tmprc = SMB2_rename(xid, tcon, persist_fid, volatile_fid,
(__le16 *)data);
break;
+ case SMB2_OP_HARDLINK:
+ tmprc = SMB2_set_hardlink(xid, tcon, persist_fid, volatile_fid,
+ (__le16 *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
diff --git a/fs/cifs/smb2link.c b/fs/cifs/smb2link.c
new file mode 100644
index 0000000..8bac250
--- /dev/null
+++ b/fs/cifs/smb2link.c
@@ -0,0 +1,108 @@
+/*
+ * fs/cifs/smb2link.c
+ *
+ * Copyright (C) 2011
+ * Author(s): Pavel Shilovsky (piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org),
+ * Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
+ *
+ * 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/namei.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "smb2glob.h"
+#include "smb2proto.h"
+
+int
+smb2_hardlink(struct dentry *old_file, struct inode *inode,
+ struct dentry *direntry)
+{
+ int rc = -EACCES;
+ int xid;
+ __le16 *from_name = NULL;
+ __le16 *to_name = NULL;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ xid = GetXid();
+
+ from_name = build_ucspath_from_dentry(old_file);
+ to_name = build_ucspath_from_dentry(direntry);
+ if ((from_name == NULL) || (to_name == NULL)) {
+ rc = -ENOMEM;
+ goto smb2_hl_exit;
+ }
+
+ rc = smb2_open_op_close(xid, tcon, from_name, FILE_READ_ATTRIBUTES,
+ FILE_OPEN, 0, 0, to_name, SMB2_OP_HARDLINK);
+
+ 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 (old_file->d_inode) {
+ cinode = CIFS_I(old_file->d_inode);
+ if (rc == 0) {
+ old_file->d_inode->i_nlink++;
+/* 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.
+ */
+ cinode->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;
+ */
+ }
+
+smb2_hl_exit:
+ kfree(from_name);
+ kfree(to_name);
+ FreeXid(xid);
+ cifs_put_tlink(tlink);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e5373da..308dd36 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1965,7 +1965,7 @@ set_delete_exit:
}
int SMB2_set_hardlink(const int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+ u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
{
struct set_info_req *pSMB2;
struct set_info_rsp *pSMB2r = NULL;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 0ed7773..4e7337c 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -109,6 +109,10 @@ extern int smb2_query_file_info(struct file *filp);
extern int smb2_query_inode_info(struct inode **pinode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid);
+extern int smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
+ __u32 desired_access, __u32 create_disposition,
+ __u32 file_attributes, __u32 create_options,
+ void *data, int command);
extern void smb2_set_ops(struct inode *inode);
extern bool smb2_is_size_safe_to_change(struct smb2_inode *smb2_ind,
__u64 end_of_file);
@@ -156,6 +160,8 @@ extern int smb2_rmdir(struct inode *inode, struct dentry *direntry);
extern int smb2_unlink(struct inode *dir, struct dentry *dentry);
extern int smb2_rename(struct inode *source_dir, struct dentry *source_dentry,
struct inode *target_dir, struct dentry *target_dentry);
+extern int smb2_hardlink(struct dentry *old_file, struct inode *inode,
+ struct dentry *direntry);
extern int smb2_readdir(struct file *file, void *direntry, filldir_t filldir);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 39/53] CIFS: Add SMB2 support for flush operation
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (18 preceding siblings ...)
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 42/53] CIFS: Process oplocks for SMB2 Pavel Shilovsky
` (3 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsglob.h | 1 +
fs/cifs/cifsproto.h | 5 +++++
fs/cifs/file.c | 34 +++++++++++++++++++++++++---------
fs/cifs/smb2file.c | 30 ++++++++++++++++++++++++------
fs/cifs/smb2proto.h | 6 ++++--
5 files changed, 59 insertions(+), 17 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index d878378..b71c3fc 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -656,6 +656,7 @@ typedef int (iread_callback_t)(int, struct cifsFileInfo *,
typedef int (read_callback_t)(int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *, char **,
int *, unsigned int);
+typedef int (fsync_callback_t)(int, struct cifsFileInfo *);
/*
* Take a reference on the file private data. Must be called with
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 4285c10..c8b1d50 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -220,6 +220,11 @@ extern int is_dir_changed(struct file *file);
extern struct dentry *cifs_readdir_lookup(struct dentry *parent,
struct qstr *name,
struct cifs_fattr *fattr);
+extern int cifs_strict_fsync_generic(struct file *file, loff_t start,
+ loff_t end, int datasync,
+ fsync_callback_t *fsync_cb);
+extern int cifs_fsync_generic(struct file *file, loff_t start, loff_t end,
+ int datasync, fsync_callback_t *fsync_cb);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 22cf18b..2c9471c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2044,12 +2044,17 @@ int cifs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
return rc;
}
-int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
- int datasync)
+static int
+cifs_fsync_cb(int xid, struct cifsFileInfo *cfile)
+{
+ return CIFSSMBFlush(xid, tlink_tcon(cfile->tlink), cfile->netfid);
+}
+
+int cifs_strict_fsync_generic(struct file *file, loff_t start, loff_t end,
+ int datasync, fsync_callback_t *fsync_cb)
{
int xid;
int rc = 0;
- struct cifs_tcon *tcon;
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);
@@ -2072,20 +2077,26 @@ 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 = fsync_cb(xid, smbfile);
FreeXid(xid);
mutex_unlock(&inode->i_mutex);
return rc;
}
-int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+int
+cifs_strict_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ return cifs_strict_fsync_generic(file, datasync, start, end,
+ cifs_fsync_cb);
+}
+
+int cifs_fsync_generic(struct file *file, loff_t start, loff_t end,
+ int datasync, fsync_callback_t *fsync_cb)
{
int xid;
int rc = 0;
- struct cifs_tcon *tcon;
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;
@@ -2100,15 +2111,20 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
cFYI(1, "Sync file - name: %s datasync: 0x%x",
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->netfid);
+ rc = fsync_cb(xid, smbfile);
FreeXid(xid);
mutex_unlock(&inode->i_mutex);
return rc;
}
+int
+cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ return cifs_fsync_generic(file, start, end, datasync, cifs_fsync_cb);
+}
+
/*
* As file closes, flush all cached write data for this inode checking
* for write behind errors.
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 48e2a36..ae4ea13 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -43,7 +43,7 @@ const struct file_operations smb2_file_ops = {
.open = smb2_open,
.release = cifs_close,
.lock = cifs_lock,
- .fsync = cifs_fsync,
+ .fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
@@ -62,7 +62,7 @@ const struct file_operations smb2_file_strict_ops = {
.open = smb2_open,
.release = cifs_close,
.lock = cifs_lock,
- .fsync = cifs_strict_fsync,
+ .fsync = smb2_strict_fsync,
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
@@ -82,7 +82,7 @@ const struct file_operations smb2_file_direct_ops = {
.open = smb2_open,
.release = cifs_close,
.lock = cifs_lock,
- .fsync = cifs_fsync,
+ .fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
@@ -100,7 +100,7 @@ const struct file_operations smb2_file_nobrl_ops = {
.aio_write = cifs_file_aio_write,
.open = smb2_open,
.release = cifs_close,
- .fsync = cifs_fsync,
+ .fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
@@ -118,7 +118,7 @@ const struct file_operations smb2_file_strict_nobrl_ops = {
.aio_write = cifs_strict_writev,
.open = smb2_open,
.release = cifs_close,
- .fsync = cifs_strict_fsync,
+ .fsync = smb2_strict_fsync,
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
@@ -137,7 +137,7 @@ const struct file_operations smb2_file_direct_nobrl_ops = {
.aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
- .fsync = cifs_fsync,
+ .fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
@@ -473,3 +473,21 @@ smb2_readpages(struct file *file, struct address_space *mapping,
return cifs_readpages_generic(file, mapping, page_list, num_pages,
smb2_async_readv);
}
+
+static int
+smb2_fsync_cb(int xid, struct cifsFileInfo *cfile)
+{
+ return SMB2_flush(xid, tlink_tcon(cfile->tlink), cfile->persist_fid,
+ cfile->volatile_fid);
+}
+
+int smb2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ return cifs_fsync_generic(file, start, end, datasync, smb2_fsync_cb);
+}
+
+int smb2_strict_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ return cifs_strict_fsync_generic(file, start, end, datasync,
+ smb2_fsync_cb);
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 4e7337c..ea44077 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -124,8 +124,6 @@ extern void smb2_allinfo_to_fattr(struct cifs_fattr *attr,
extern void smb2_create_dfs_attr(struct cifs_fattr *fattr,
struct super_block *sb);
extern void cifs_fattr_to_inode(struct inode *pinode, struct cifs_fattr *attr);
-extern int smb2_fsync(struct file *file, int datasync);
-extern int smb2_flush(struct file *file, fl_owner_t id);
extern struct cifsFileInfo *smb2_new_fileinfo(__u64 persist_fid,
__u64 volatile_fid,
struct file *file,
@@ -142,6 +140,10 @@ extern int smb2_write_cb(int xid, struct cifsFileInfo *cfile,
struct cifs_io_parms *parms, unsigned int *written,
struct kvec *iov, unsigned long nr_segs,
unsigned int remaining_bytes, int timeout);
+extern int smb2_strict_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync);
+extern int smb2_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync);
extern int smb2_open(struct inode *inode, struct file *file);
extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 40/53] CIFS: Add NTLMSSP sec type to defaults
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (17 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 38/53] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 41/53] CIFS: Disable SMB2.1 protocol negotiating Pavel Shilovsky
` (8 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsglob.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b71c3fc..c05b4c0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -998,7 +998,7 @@ require use of the stronger protocol */
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
#define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */
-#define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
+#define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP)
#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 41/53] CIFS: Disable SMB2.1 protocol negotiating
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (18 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 40/53] CIFS: Add NTLMSSP sec type to defaults Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 43/53] CIFS: Process STATUS_PENDING responses for SMB2 Pavel Shilovsky
` (7 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
because we don't support it now.
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2pdu.c | 2 +-
fs/cifs/transport.c | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 308dd36..4b66a76 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -525,7 +525,7 @@ static void free_rsp_buf(int resp_buftype, void *pSMB2r)
cifs_buf_release(pSMB2r);
}
-#define SMB2_NUM_PROT 2
+#define SMB2_NUM_PROT 1
#define SMB2_PROT 0
#define SMB21_PROT 1
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index bfae7d9..e205d2a 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -294,8 +294,11 @@ int wait_for_free_request(struct TCP_Server_Info *server,
(atomic_read(&server->credits) < 1)) {
spin_unlock(&GlobalMid_Lock);
cifs_num_waiters_inc(server);
- wait_event(server->request_q,
- atomic_read(&server->credits) > 0);
+ if (wait_event_killable(server->request_q,
+ atomic_read(&server->credits) > 0)) {
+ cifs_num_waiters_dec(server);
+ return -ENOENT;
+ }
cifs_num_waiters_dec(server);
spin_lock(&GlobalMid_Lock);
#endif /* CONFIG_CIFS_SMB2 */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 42/53] CIFS: Process oplocks for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (19 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 39/53] CIFS: Add SMB2 support for flush operation Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 46/53] CIFS: Add strictcache i/o " Pavel Shilovsky
` (2 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/cifsproto.h | 3 +--
fs/cifs/connect.c | 4 +++-
fs/cifs/file.c | 15 ++++++---------
fs/cifs/smb2file.c | 35 ++++++++++++++++++++++++++++-------
fs/cifs/smb2inode.c | 15 +++++++--------
fs/cifs/smb2pdu.c | 9 +++++----
fs/cifs/smb2proto.h | 5 +++--
fs/cifs/smb2readdir.c | 4 +++-
8 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c8b1d50..4f1045b 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -131,8 +131,7 @@ extern struct cifsFileInfo *cifs_new_fileinfo(__u16 netfid, struct file *file,
struct tcon_link *tlink,
__u32 oplock);
extern struct cifsFileInfo *cifs_new_fileinfo_generic(struct file *file,
- struct tcon_link *tlink,
- __u32 oplock);
+ struct tcon_link *tlink);
extern int cifs_posix_open(const char *full_path, struct inode **pinode,
struct super_block *sb, int mode,
unsigned int f_flags, __u32 *poplock, __u16 *pnetfid,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index d3752e0..ab9e972 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3174,9 +3174,11 @@ is_path_accessible(int xid, struct cifs_tcon *tcon,
#ifdef CONFIG_CIFS_SMB2
if (tcon->ses->server->is_smb2) {
__u64 persistent_fid, volatile_fid;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+
rc = SMB2_open(xid, tcon, (__le16 *)full_path, &persistent_fid,
&volatile_fid, FILE_READ_ATTRIBUTES, FILE_OPEN,
- 0, 0);
+ 0, 0, &oplock);
if (rc)
return rc;
/* rc = SMB2_query_info() */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2c9471c..09655f7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -249,17 +249,19 @@ cifs_new_fileinfo(__u16 netfid, struct file *file,
struct tcon_link *tlink, __u32 oplock)
{
struct cifsFileInfo *cifs_file;
+ struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
- cifs_file = cifs_new_fileinfo_generic(file, tlink, oplock);
+ cifs_file = cifs_new_fileinfo_generic(file, tlink);
if (cifs_file == NULL)
return NULL;
cifs_file->netfid = netfid;
+ cifs_set_oplock_level(cinode, oplock);
+ cinode->can_cache_brlcks = cinode->clientCanCacheAll;
return cifs_file;
}
struct cifsFileInfo *
-cifs_new_fileinfo_generic(struct file *file, struct tcon_link *tlink,
- __u32 oplock)
+cifs_new_fileinfo_generic(struct file *file, struct tcon_link *tlink)
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
@@ -289,9 +291,6 @@ cifs_new_fileinfo_generic(struct file *file, struct tcon_link *tlink,
list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
spin_unlock(&cifs_file_list_lock);
- cifs_set_oplock_level(pCifsInode, oplock);
- pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
-
file->private_data = pCifsFile;
return pCifsFile;
}
@@ -552,6 +551,7 @@ cifs_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
reopen_success:
cifs_file->netfid = netfid;
+ cifs_set_oplock_level(CIFS_I(inode), *oplock);
reopen_error_exit:
return rc;
}
@@ -566,7 +566,6 @@ cifs_reopen_file_generic(struct cifsFileInfo *cifs_file, bool can_flush,
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
struct inode *inode;
- struct cifsInodeInfo *cifs_inode;
char *full_path = NULL;
xid = GetXid();
@@ -603,7 +602,6 @@ cifs_reopen_file_generic(struct cifsFileInfo *cifs_file, bool can_flush,
mutex_unlock(&cifs_file->fh_mutex);
if (rc)
goto out;
- cifs_inode = CIFS_I(inode);
if (can_flush) {
rc = filemap_write_and_wait(inode->i_mapping);
@@ -622,7 +620,6 @@ cifs_reopen_file_generic(struct cifsFileInfo *cifs_file, bool can_flush,
we can not go to the server to get the new inod
info */
- cifs_set_oplock_level(cifs_inode, oplock);
cifs_relock_file(cifs_file);
cifs_file->invalidHandle = false;
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index ae4ea13..8b0080b 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -178,17 +178,37 @@ const struct address_space_operations smb2_addr_ops_smallbuf = {
.launder_page = cifs_launder_page,
};
+static void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock)
+{
+ 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;
+ }
+}
+
struct cifsFileInfo *
smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
- struct tcon_link *tlink, __u32 oplock)
+ struct tcon_link *tlink, __u8 oplock)
{
struct cifsFileInfo *cifs_file;
- cifs_file = cifs_new_fileinfo_generic(file, tlink, oplock);
+ cifs_file = cifs_new_fileinfo_generic(file, tlink);
if (cifs_file == NULL)
return NULL;
cifs_file->persist_fid = persist_fid;
cifs_file->volatile_fid = volatile_fid;
+ smb2_set_oplock_level(CIFS_I(file->f_path.dentry->d_inode), oplock);
return cifs_file;
}
@@ -220,9 +240,9 @@ smb2_open_helper(struct file *file, struct inode *inode, const char *full_path,
goto out;
}
+ *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
- desired_access, create_disposition, 0, 0);
-
+ desired_access, create_disposition, 0, 0, oplock);
if (rc)
goto out;
@@ -234,7 +254,6 @@ smb2_open_helper(struct file *file, struct inode *inode, const char *full_path,
move_smb2_info_to_cifs(data, smb2_data);
out:
- *oplock = 0;
kfree(smb2_data);
kfree(smb2_path);
return rc;
@@ -335,8 +354,10 @@ smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
goto reopen_error_exit;
}
+ *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
rc = SMB2_open(xid, tcon, smb2_path, &persist_fid, &volatile_fid,
- desired_access, create_disposition, 0, 0);
+ desired_access, create_disposition, 0, 0,
+ (__u8 *)oplock);
if (rc) {
mutex_unlock(&cifs_file->fh_mutex);
cFYI(1, "cifs_open returned 0x%x", rc);
@@ -346,7 +367,7 @@ smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
cifs_file->persist_fid = persist_fid;
cifs_file->volatile_fid = volatile_fid;
- *oplock = 0;
+ smb2_set_oplock_level(CIFS_I(inode), *oplock);
reopen_error_exit:
kfree(smb2_path);
return rc;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 8e69650..aecf50f 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -148,10 +148,11 @@ smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
{
int rc, tmprc = 0;
u64 persist_fid, volatile_fid;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
rc = SMB2_open(xid, tcon, path, &persist_fid, &volatile_fid,
desired_access, create_disposition, file_attributes,
- create_options);
+ create_options, &oplock);
if (rc)
return rc;
@@ -581,7 +582,7 @@ unlink_out:
static int
smb2_create_helper(struct inode *dir, struct dentry *direntry, int mode,
- struct nameidata *nd, __u32 *oplock, __u64 *persist_fid,
+ struct nameidata *nd, __u8 *oplock, __u64 *persist_fid,
__u64 *volatile_fid, int xid, struct cifs_tcon *tcon,
const char *full_path, void *data)
{
@@ -629,8 +630,10 @@ smb2_create_helper(struct inode *dir, struct dentry *direntry, int mode,
goto out;
}
+ *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
- desired_access, create_disposition, 0, create_options);
+ desired_access, create_disposition, 0, create_options,
+ oplock);
if (rc)
goto out;
@@ -651,7 +654,6 @@ smb2_create_helper(struct inode *dir, struct dentry *direntry, int mode,
move_smb2_info_to_cifs(data, smb2_data);
out:
- *oplock = 0;
kfree(smb2_data);
kfree(smb2_path);
return rc;
@@ -663,7 +665,7 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
{
int rc = -ENOENT;
int xid;
- __u32 oplock = 0;
+ __u8 oplock = 0;
/*
* BB below access is probably too much for mknod to request
* but we have to do query and setpathinfo so requesting
@@ -689,9 +691,6 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
}
tcon = tlink_tcon(tlink);
- if (oplockEnabled)
- oplock = REQ_OPLOCK;
-
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (!buf)
return -ENOMEM;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 4b66a76..bd69274 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1047,7 +1047,7 @@ int SMB2_tdis(const int xid, struct cifs_tcon *tcon)
int SMB2_open(const 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_options, __u8 *oplock)
{
struct create_req *pSMB2;
struct create_rsp *pSMB2r;
@@ -1071,9 +1071,9 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
if (rc)
return rc;
- /* if (enable_oplocks)
- pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
- else */
+ if (enable_oplocks)
+ pSMB2->RequestedOplockLevel = *oplock;
+ else
pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
pSMB2->ImpersonationLevel = IL_IMPERSONATION;
pSMB2->DesiredAccess = cpu_to_le32(desired_access);
@@ -1124,6 +1124,7 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
}
*persistent_fid = pSMB2r->PersistentFileId;
*volatile_fid = pSMB2r->VolatileFileId;
+ *oplock = pSMB2r->OplockLevel;
creat_exit:
free_rsp_buf(resp_buftype, pSMB2r);
return rc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index ea44077..2408be1 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -128,7 +128,7 @@ extern struct cifsFileInfo *smb2_new_fileinfo(__u64 persist_fid,
__u64 volatile_fid,
struct file *file,
struct tcon_link *tlink,
- __u32 oplock);
+ __u8 oplock);
extern int smb2_reopen_file_cb(struct cifsFileInfo *cifs_file, int xid,
struct cifs_tcon *tcon, const char *full_path,
__u32 *oplock);
@@ -219,7 +219,8 @@ extern int SMB2_rename(const int xid, struct cifs_tcon *tcon,
extern int SMB2_open(const 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,
+ __u8 *oplock);
extern int SMB2_symlink_ioctl(const int, struct cifs_tcon *, u32, u64, u64,
const char *);
extern int SMB2_close(const int xid, struct cifs_tcon *tcon,
diff --git a/fs/cifs/smb2readdir.c b/fs/cifs/smb2readdir.c
index 9598cf8..c6aceda 100644
--- a/fs/cifs/smb2readdir.c
+++ b/fs/cifs/smb2readdir.c
@@ -398,6 +398,7 @@ static int initiate_smb2_search(const int xid, struct file *file)
struct cifs_tcon *tcon;
struct tcon_link *tlink;
u64 persistent_fid, volatile_fid;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
smb2_sb = CIFS_SB(file->f_path.dentry->d_sb);
tlink = cifs_sb_tlink(smb2_sb);
@@ -412,7 +413,8 @@ static int initiate_smb2_search(const int xid, struct file *file)
return -ENOMEM;
rc = SMB2_open(xid, tcon, full_path, &persistent_fid, &volatile_fid,
- FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0);
+ FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
+ &oplock);
if (rc) {
cERROR(1, "open of dir failed before readdir with rc = %d", rc);
goto initiate_search_exit;
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 43/53] CIFS: Process STATUS_PENDING responses for SMB2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (19 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 41/53] CIFS: Disable SMB2.1 protocol negotiating Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 44/53] CIFS: Request SMB2.1 leases Pavel Shilovsky
` (6 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/connect.c | 19 +++++++++++++++++--
fs/cifs/nterr.h | 1 +
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ab9e972..e46c2bd 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -825,10 +825,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
* into the payload for debugging purposes.
*/
#ifdef CONFIG_CIFS_SMB2
- if (server->is_smb2)
+ if (server->is_smb2) {
length = checkSMB2(smb2_buffer, smb2_buffer->MessageId,
server->total_read);
- else
+ } else
#endif
length = checkSMB(smb_buffer, smb_buffer->Mid,
server->total_read);
@@ -836,6 +836,21 @@ 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));
+#ifdef CONFIG_CIFS_SMB2
+ /*
+ * If we negotiate SMB2 protocol and get STATUS_PENDING - update
+ * the number of credits and skip it.
+ */
+ if (server->is_smb2 &&
+ le32_to_cpu(smb2_buffer->Status) == STATUS_PENDING) {
+ if (!length)
+ atomic_add(le16_to_cpu(smb2_buffer->CreditRequest),
+ &server->credits);
+ cERROR(1, "STATUS PENDING");
+ return -1;
+ }
+#endif
+
if (mid)
handle_mid(mid, server, buf, length);
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h
index 2572673..e80c0ef 100644
--- a/fs/cifs/nterr.h
+++ b/fs/cifs/nterr.h
@@ -40,6 +40,7 @@ extern const struct nt_err_code_struct nt_errs[];
#define ERROR_INSUFFICIENT_BUFFER 0x007a
#define STATUS_1804 0x070c
#define STATUS_NOTIFY_ENUM_DIR 0x010c
+#define STATUS_PENDING 0x00000103
/* Win32 Error codes extracted using a loop in smbclient then printing a
netmon sniff to a file. */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 44/53] CIFS: Request SMB2.1 leases
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (20 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 43/53] CIFS: Process STATUS_PENDING responses for SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 45/53] CIFS: Process oplock/lease break for SMB2/2.1 Pavel Shilovsky
` (5 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
if server supports them and we need oplocks.
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsfs.c | 5 ++-
fs/cifs/cifsglob.h | 3 +
fs/cifs/smb2file.c | 9 ++-
fs/cifs/smb2inode.c | 12 +++--
fs/cifs/smb2pdu.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++---
fs/cifs/smb2pdu.h | 31 +++++++++++-
6 files changed, 185 insertions(+), 17 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 7991a53..3683384 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -36,6 +36,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/namei.h>
+#include <linux/random.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
@@ -263,7 +264,9 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->server_eof = 0;
cifs_inode->uniqueid = 0;
cifs_inode->createtime = 0;
-
+#ifdef CONFIG_CIFS_SMB2
+ get_random_bytes(&cifs_inode->lease_key, 16);
+#endif
/* Can not set i_flags here - they get immediately overwritten
to zero by the VFS */
/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c05b4c0..3d950d9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -692,6 +692,9 @@ struct cifsInodeInfo {
struct fscache_cookie *fscache;
#endif
struct inode vfs_inode;
+#ifdef CONFIG_CIFS_SMB2
+ __u8 lease_key[16];
+#endif
};
static inline struct cifsInodeInfo *
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 8b0080b..58f9edb 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -241,6 +241,9 @@ smb2_open_helper(struct file *file, struct inode *inode, const char *full_path,
}
*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ if (tcon->ses->server->smb2_dialect_revision == cpu_to_le16(0x0210))
+ memcpy(oplock + 1, &CIFS_I(inode)->lease_key, 16);
+
rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
desired_access, create_disposition, 0, 0, oplock);
if (rc)
@@ -263,7 +266,7 @@ int smb2_open(struct inode *inode, struct file *file)
{
int rc = -EACCES;
int xid;
- __u8 oplock;
+ __u8 oplock[17];
struct cifs_sb_info *cifs_sb;
struct cifsFileInfo *cifs_file;
struct tcon_link *tlink;
@@ -294,7 +297,7 @@ int smb2_open(struct inode *inode, struct file *file)
goto out;
}
- rc = smb2_open_helper(file, inode, full_path, &oplock, &persist_fid,
+ rc = smb2_open_helper(file, inode, full_path, oplock, &persist_fid,
&volatile_fid, data, tcon, xid);
if (rc)
goto out;
@@ -306,7 +309,7 @@ int smb2_open(struct inode *inode, struct file *file)
}
cifs_file = smb2_new_fileinfo(persist_fid, volatile_fid, file, tlink,
- oplock);
+ *oplock);
if (cifs_file == NULL) {
SMB2_close(xid, tcon, persist_fid, volatile_fid);
rc = -ENOMEM;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index aecf50f..012b335 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -631,6 +631,9 @@ smb2_create_helper(struct inode *dir, struct dentry *direntry, int mode,
}
*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ if (tcon->ses->server->smb2_dialect_revision == cpu_to_le16(0x0210))
+ get_random_bytes(oplock + 1, 16);
+
rc = SMB2_open(xid, tcon, smb2_path, persist_fid, volatile_fid,
desired_access, create_disposition, 0, create_options,
oplock);
@@ -665,7 +668,7 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
{
int rc = -ENOENT;
int xid;
- __u8 oplock = 0;
+ __u8 oplock[17];
/*
* BB below access is probably too much for mknod to request
* but we have to do query and setpathinfo so requesting
@@ -701,7 +704,7 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
goto smb2_create_out;
}
- rc = smb2_create_helper(dir, direntry, mode, nd, &oplock, &persist_fid,
+ rc = smb2_create_helper(dir, direntry, mode, nd, oplock, &persist_fid,
&volatile_fid, xid, tcon, full_path, buf);
if (rc) {
cFYI(1, "smb2_create returned 0x%x", rc);
@@ -716,9 +719,10 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
}
if (newinode) {
+ memcpy(CIFS_I(newinode)->lease_key, oplock + 1, 16);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
- if ((oplock & CIFS_CREATE_ACTION) &&
+ if ((*oplock & CIFS_CREATE_ACTION) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
newinode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID)
@@ -742,7 +746,7 @@ smb2_create(struct inode *dir, struct dentry *direntry, int mode,
}
file_info = smb2_new_fileinfo(persist_fid, volatile_fid,
- filp, tlink, oplock);
+ filp, tlink, *oplock);
if (file_info == NULL) {
fput(filp);
SMB2_close(xid, tcon, persist_fid, volatile_fid);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index bd69274..bcc3513 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -525,7 +525,7 @@ static void free_rsp_buf(int resp_buftype, void *pSMB2r)
cifs_buf_release(pSMB2r);
}
-#define SMB2_NUM_PROT 1
+#define SMB2_NUM_PROT 2
#define SMB2_PROT 0
#define SMB21_PROT 1
@@ -610,6 +610,7 @@ SMB2_negotiate(unsigned int xid, struct cifs_ses *ses)
pSMB2->SecurityMode = cpu_to_le16(temp);
pSMB2->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS);
+ pSMB2->ClientGUID[0] = pSMB2->ClientGUID[3] = pSMB2->ClientGUID[7] = 7;
iov[0].iov_base = (char *)pSMB2;
iov[0].iov_len = be32_to_cpu(pSMB2->hdr.smb2_buf_length) + 4;
@@ -1044,6 +1045,87 @@ int SMB2_tdis(const int xid, struct cifs_tcon *tcon)
return rc;
}
+static struct create_lease *
+create_lease_buf(u8 *lease_key, u8 oplock)
+{
+ struct create_lease *buf;
+
+ buf = kmalloc(sizeof(struct create_lease), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ memset(buf, 0, sizeof(struct create_lease));
+
+ buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
+ buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
+ if (enable_oplocks) {
+ if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+ buf->lcontext.LeaseState = SMB2_LEASE_WRITE_CACHING |
+ SMB2_LEASE_READ_CACHING;
+ else if (oplock == SMB2_OPLOCK_LEVEL_II)
+ buf->lcontext.LeaseState = SMB2_LEASE_READ_CACHING;
+ else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
+ buf->lcontext.LeaseState = SMB2_LEASE_HANDLE_CACHING |
+ SMB2_LEASE_READ_CACHING |
+ SMB2_LEASE_WRITE_CACHING;
+ }
+
+ buf->ccontext.DataOffset = cpu_to_le16(offsetof
+ (struct create_lease, lcontext));
+ buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
+ buf->ccontext.NameOffset = cpu_to_le16(offsetof
+ (struct create_lease, Name));
+ buf->ccontext.NameLength = cpu_to_le16(4);
+ buf->Name[0] = 'R';
+ buf->Name[1] = 'q';
+ buf->Name[2] = 'L';
+ buf->Name[3] = 's';
+ return buf;
+}
+
+static __u8
+parse_lease_state(struct create_rsp *smb)
+{
+ char *data_offset;
+ struct create_lease *lc;
+ __u8 oplock = 0;
+ bool found = false;
+
+ data_offset = (char *)smb;
+ data_offset += 4 + le32_to_cpu(smb->CreateContextsOffset);
+ lc = (struct create_lease *)data_offset;
+ do {
+ char *name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
+ if (le16_to_cpu(lc->ccontext.NameLength) != 4) {
+ lc = (struct create_lease *)((char *)lc
+ + le32_to_cpu(lc->ccontext.Next));
+ continue;
+ }
+ if (strncmp(name, "RqLs", 4)) {
+ lc = (struct create_lease *)((char *)lc
+ + le32_to_cpu(lc->ccontext.Next));
+ continue;
+ }
+ found = true;
+ break;
+ } while (le32_to_cpu(lc->ccontext.Next) != 0);
+
+ if (!found)
+ return oplock;
+
+ if (le32_to_cpu(lc->lcontext.LeaseState) & SMB2_LEASE_WRITE_CACHING) {
+ if (le32_to_cpu(lc->lcontext.LeaseState) &
+ SMB2_LEASE_HANDLE_CACHING)
+ oplock = SMB2_OPLOCK_LEVEL_BATCH;
+ else
+ oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ } else if (le32_to_cpu(lc->lcontext.LeaseState) &
+ SMB2_LEASE_READ_CACHING)
+ oplock = SMB2_OPLOCK_LEVEL_II;
+
+ return oplock;
+}
+
int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
__u32 create_disposition, __u32 file_attributes,
@@ -1053,10 +1135,12 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
struct create_rsp *pSMB2r;
struct TCP_Server_Info *server;
struct cifs_ses *ses = tcon->ses;
- struct kvec iov[2];
+ struct kvec iov[3];
int resp_buftype;
int status;
int uni_path_len;
+ __le16 *copy_path = NULL;
+ int copy_size;
int rc = 0;
int num_iovecs = 2;
@@ -1071,10 +1155,6 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
if (rc)
return rc;
- if (enable_oplocks)
- pSMB2->RequestedOplockLevel = *oplock;
- else
- pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
pSMB2->ImpersonationLevel = IL_IMPERSONATION;
pSMB2->DesiredAccess = cpu_to_le32(desired_access);
/* File attributes ignored on open (used in create though) */
@@ -1084,7 +1164,7 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
pSMB2->CreateOptions = cpu_to_le32(create_options);
uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
pSMB2->NameOffset = cpu_to_le16(sizeof(struct create_req)
- - 1 /* pad */ - 4 /* do not count rfc1001 len field */);
+ - 8 /* pad */ - 4 /* do not count rfc1001 len field */);
iov[0].iov_base = (char *)pSMB2;
@@ -1096,16 +1176,57 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
pSMB2->NameLength = cpu_to_le16(uni_path_len - 2);
/* -1 since last byte is buf[0] which is sent below (path) */
iov[0].iov_len--;
+ if (uni_path_len % 8 != 0) {
+ copy_size = uni_path_len / 8 * 8;
+ if (copy_size < uni_path_len)
+ copy_size += 8;
+
+ copy_path = kzalloc(copy_size, GFP_KERNEL);
+ if (!copy_path)
+ return -ENOMEM;
+ memcpy((char *)copy_path, (const char *)path,
+ uni_path_len);
+ uni_path_len = copy_size;
+ path = copy_path;
+ }
+
iov[1].iov_len = uni_path_len;
iov[1].iov_base = path;
/* -1 since last byte is buf[0] which was counted in smb2_buf_len */
pSMB2->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
pSMB2->hdr.smb2_buf_length) + uni_path_len - 1);
} else {
+ iov[0].iov_len += 7;
+ pSMB2->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
+ pSMB2->hdr.smb2_buf_length) + 8 - 1);
num_iovecs = 1;
pSMB2->NameLength = 0;
}
+ if (!enable_oplocks)
+ *oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+ if (tcon->ses->server->smb2_dialect_revision == cpu_to_le16(0x0202) ||
+ *oplock == SMB2_OPLOCK_LEVEL_NONE)
+ pSMB2->RequestedOplockLevel = *oplock;
+ else {
+ iov[num_iovecs].iov_base = create_lease_buf(oplock+1, *oplock);
+ if (iov[num_iovecs].iov_base == NULL) {
+ cifs_small_buf_release(pSMB2);
+ kfree(copy_path);
+ return -ENOMEM;
+ }
+ iov[num_iovecs].iov_len = sizeof(struct create_lease);
+ pSMB2->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
+ pSMB2->CreateContextsOffset = cpu_to_le32(
+ sizeof(struct create_req) - 4 - 8 +
+ iov[num_iovecs-1].iov_len);
+ pSMB2->CreateContextsLength = cpu_to_le32(
+ sizeof(struct create_lease));
+ inc_rfc1001_len(&pSMB2->hdr, sizeof(struct create_lease));
+ num_iovecs++;
+ }
+
/* cERROR(1, "unipathlen 0x%x iov0len 0x%x iov1len 0x%x", uni_path_len,
iov[0].iov_len, iov[1].iov_len); */ /* BB REMOVEME BB */
rc = smb2_sendrcv2(xid, ses, iov, num_iovecs, &resp_buftype /* ret */,
@@ -1124,8 +1245,13 @@ int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
}
*persistent_fid = pSMB2r->PersistentFileId;
*volatile_fid = pSMB2r->VolatileFileId;
- *oplock = pSMB2r->OplockLevel;
+
+ if (pSMB2r->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
+ *oplock = parse_lease_state(pSMB2r);
+ else
+ *oplock = pSMB2r->OplockLevel;
creat_exit:
+ kfree(copy_path);
free_rsp_buf(resp_buftype, pSMB2r);
return rc;
}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index a24dfdb..6b8fd2f 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -438,7 +438,7 @@ struct create_req {
__le16 NameLength;
__le32 CreateContextsOffset;
__le32 CreateContextsLength;
- __u8 Buffer[1];
+ __u8 Buffer[8];
} __attribute__((packed));
struct create_rsp {
@@ -462,6 +462,35 @@ struct create_rsp {
__u8 Buffer[1];
} __attribute__((packed));
+struct create_context {
+ __le32 Next;
+ __le16 NameOffset;
+ __le16 NameLength;
+ __le16 Reserved;
+ __le16 DataOffset;
+ __le32 DataLength;
+ __u8 Buffer[0];
+} __attribute__((packed));
+
+#define SMB2_LEASE_NONE cpu_to_le32(0x00)
+#define SMB2_LEASE_READ_CACHING cpu_to_le32(0x01)
+#define SMB2_LEASE_HANDLE_CACHING cpu_to_le32(0x02)
+#define SMB2_LEASE_WRITE_CACHING cpu_to_le32(0x04)
+
+struct lease_context {
+ __le64 LeaseKeyLow;
+ __le64 LeaseKeyHigh;
+ __le32 LeaseState;
+ __le32 LeaseFlags;
+ __le64 LeaseDuration;
+} __attribute__((packed));
+
+struct create_lease {
+ struct create_context ccontext;
+ u8 Name[8];
+ struct lease_context lcontext;
+} __attribute__((packed));
+
/* Currently defined values for close flags */
#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001)
struct close_req {
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 45/53] CIFS: Process oplock/lease break for SMB2/2.1
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (21 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 44/53] CIFS: Request SMB2.1 leases Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 47/53] CIFS: Enable signing in SMB2 Pavel Shilovsky
` (4 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +
fs/cifs/cifsproto.h | 4 +-
fs/cifs/connect.c | 2 +-
fs/cifs/file.c | 24 +++++--
fs/cifs/misc.c | 11 ++-
fs/cifs/smb2file.c | 39 ++++++------
fs/cifs/smb2misc.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2pdu.c | 90 ++++++++++++++++++++------
fs/cifs/smb2pdu.h | 35 ++++++++++
fs/cifs/smb2proto.h | 14 +++-
10 files changed, 348 insertions(+), 54 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3d950d9..56962a5 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -697,6 +697,9 @@ struct cifsInodeInfo {
#endif
};
+typedef int (oplock_callback_t)(struct cifs_tcon *, struct cifsInodeInfo *,
+ struct cifsFileInfo *);
+
static inline struct cifsInodeInfo *
CIFS_I(struct inode *inode)
{
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 4f1045b..a61da92 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -94,7 +94,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
struct smb_hdr *out_buf,
int *bytes_returned);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
-extern bool is_valid_oplock_break(struct smb_hdr *smb,
+extern bool is_valid_oplock_break(char *buffer,
struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
@@ -132,6 +132,8 @@ extern struct cifsFileInfo *cifs_new_fileinfo(__u16 netfid, struct file *file,
__u32 oplock);
extern struct cifsFileInfo *cifs_new_fileinfo_generic(struct file *file,
struct tcon_link *tlink);
+extern void cifs_oplock_break_generic(struct work_struct *work,
+ oplock_callback_t *oplock_cb);
extern int cifs_posix_open(const char *full_path, struct inode **pinode,
struct super_block *sb, int mode,
unsigned int f_flags, __u32 *poplock, __u16 *pnetfid,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e46c2bd..c8a94a4 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -960,7 +960,7 @@ cifs_demultiplex_thread(void *p)
if (mid_entry != NULL) {
if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry);
- } else if (!is_valid_oplock_break((void *)buf, server)) {
+ } else if (!is_valid_oplock_break(buf, server)) {
cERROR(1, "No task to wake, unknown frame received! "
"NumMids %d", atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", buf, buf_size);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 09655f7..a43856a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -257,6 +257,7 @@ cifs_new_fileinfo(__u16 netfid, struct file *file,
cifs_file->netfid = netfid;
cifs_set_oplock_level(cinode, oplock);
cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+ INIT_WORK(&cifs_file->oplock_break, cifs_oplock_break);
return cifs_file;
}
@@ -280,7 +281,6 @@ cifs_new_fileinfo_generic(struct file *file, struct tcon_link *tlink)
pCifsFile->invalidHandle = false;
pCifsFile->tlink = cifs_get_tlink(tlink);
mutex_init(&pCifsFile->fh_mutex);
- INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
spin_lock(&cifs_file_list_lock);
list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
@@ -3088,7 +3088,8 @@ int cifs_launder_page(struct page *page)
return rc;
}
-void cifs_oplock_break(struct work_struct *work)
+void cifs_oplock_break_generic(struct work_struct *work,
+ oplock_callback_t *oplock_cb)
{
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
@@ -3121,14 +3122,25 @@ 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,
- current->tgid, 0, 0, 0, 0,
- LOCKING_ANDX_OPLOCK_RELEASE, false,
- cinode->clientCanCacheRead ? 1 : 0);
+ rc = oplock_cb(tlink_tcon(cfile->tlink), cinode, cfile);
cFYI(1, "Oplock release rc = %d", rc);
}
}
+static int
+cifs_oplock_cb(struct cifs_tcon *tcon, struct cifsInodeInfo *cinode,
+ struct cifsFileInfo *cfile)
+{
+ return CIFSSMBLock(0, tcon, cfile->netfid, current->tgid, 0, 0, 0, 0,
+ LOCKING_ANDX_OPLOCK_RELEASE, false,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
+void cifs_oplock_break(struct work_struct *work)
+{
+ cifs_oplock_break_generic(work, cifs_oplock_cb);
+}
+
const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage,
.readpages = cifs_readpages,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index d291463..88bede1 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -29,6 +29,9 @@
#include "smberr.h"
#include "nterr.h"
#include "cifs_unicode.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
@@ -505,8 +508,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
}
bool
-is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
{
+ struct smb_hdr *buf = (struct smb_hdr *)buffer;
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp, *tmp1, *tmp2;
struct cifs_ses *ses;
@@ -516,7 +520,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
#ifdef CONFIG_CIFS_SMB2
if (srv->is_smb2)
- return false;
+ return smb2_is_valid_oplock_break(buffer, srv);
#endif
cFYI(1, "Checking for oplock break or dnotify response");
@@ -592,9 +596,10 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel ? OPLOCK_READ : 0);
+ netfile->oplock_break_cancelled = false;
+
queue_work(system_nrt_wq,
&netfile->oplock_break);
- netfile->oplock_break_cancelled = false;
spin_unlock(&cifs_file_list_lock);
spin_unlock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 58f9edb..a8cb423 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -178,25 +178,6 @@ const struct address_space_operations smb2_addr_ops_smallbuf = {
.launder_page = cifs_launder_page,
};
-static void
-smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock)
-{
- 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;
- }
-}
-
struct cifsFileInfo *
smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
struct tcon_link *tlink, __u8 oplock)
@@ -209,6 +190,7 @@ smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
cifs_file->persist_fid = persist_fid;
cifs_file->volatile_fid = volatile_fid;
smb2_set_oplock_level(CIFS_I(file->f_path.dentry->d_inode), oplock);
+ INIT_WORK(&cifs_file->oplock_break, smb2_oplock_break);
return cifs_file;
}
@@ -515,3 +497,22 @@ int smb2_strict_fsync(struct file *file, loff_t start, loff_t end, int datasync)
return cifs_strict_fsync_generic(file, start, end, datasync,
smb2_fsync_cb);
}
+
+static int
+smb2_oplock_cb(struct cifs_tcon *tcon, struct cifsInodeInfo *cinode,
+ struct cifsFileInfo *cfile)
+{
+ if (tcon->ses->server->smb2_dialect_revision == cpu_to_le16(0x0210))
+ return SMB2_lease_break(0, tlink_tcon(cfile->tlink),
+ cinode->lease_key,
+ smb2_get_lease_state(cinode));
+
+ return SMB2_oplock_break(0, tlink_tcon(cfile->tlink),
+ cfile->persist_fid, cfile->volatile_fid,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
+void smb2_oplock_break(struct work_struct *work)
+{
+ cifs_oplock_break_generic(work, smb2_oplock_cb);
+}
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 6f7afdc..6b64cd8 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -151,12 +151,19 @@ checkSMB2(struct smb2_hdr *smb, __u64 mid, unsigned int length)
if (smb2_rsp_struct_sizes[command] !=
le16_to_cpu(smb2->StructureSize2)) {
- if ((smb->Status == 0) ||
- (le16_to_cpu(smb2->StructureSize2) != 9)) {
+ if (command != SMB2OPLOCK_BREAK && ((smb->Status == 0) ||
+ (le16_to_cpu(smb2->StructureSize2) != 9))) {
/* error packets have 9 byte structure size */
cERROR(1, "Illegal response size %d for command %d",
le16_to_cpu(smb2->StructureSize2), command);
return 1;
+ } else if (command == SMB2OPLOCK_BREAK && (smb->Status == 0)
+ && (le16_to_cpu(smb2->StructureSize2) != 44)
+ && (le16_to_cpu(smb2->StructureSize2) != 36)) {
+ /* special case for SMB2.1 lease break message */
+ cERROR(1, "Illegal response size %d for oplock break",
+ le16_to_cpu(smb2->StructureSize2));
+ return 1;
}
}
@@ -171,6 +178,8 @@ checkSMB2(struct smb2_hdr *smb, __u64 mid, unsigned int length)
if (4 + len != clc_len) {
cFYI(1, "Calculated size %d length %d mismatch for mid %lld",
clc_len, 4 + len, smb->MessageId);
+ if (clc_len + 20 == len && command == SMB2OPLOCK_BREAK)
+ 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;
@@ -345,3 +354,170 @@ calc_size_exit:
cFYI(1, "smb2 len %d", len);
return len;
}
+
+__le32
+smb2_get_lease_state(struct cifsInodeInfo *cinode)
+{
+ if (cinode->clientCanCacheAll)
+ return SMB2_LEASE_WRITE_CACHING;
+ else if (cinode->clientCanCacheRead)
+ return SMB2_LEASE_READ_CACHING;
+ return 0;
+}
+
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock)
+{
+ 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;
+ }
+}
+
+__u8 smb2_map_lease_to_oplock(__le32 lease_state)
+{
+ if (lease_state & SMB2_LEASE_WRITE_CACHING) {
+ if (lease_state & SMB2_LEASE_HANDLE_CACHING)
+ return SMB2_OPLOCK_LEVEL_BATCH;
+ else
+ return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ } else if (lease_state & SMB2_LEASE_READ_CACHING)
+ return SMB2_OPLOCK_LEVEL_II;
+ return 0;
+}
+
+static bool
+smb2_is_valid_lease_break(struct smb2_hdr *buf, struct TCP_Server_Info *srv)
+{
+ struct lease_break *pSMB = (struct lease_break *)buf;
+ struct list_head *tmp, *tmp1, *tmp2;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+ struct cifsFileInfo *cfile;
+
+ cFYI(1, "Checking for lease break");
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(tmp, &srv->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);
+ cinode = CIFS_I(cfile->dentry->d_inode);
+
+ if (memcmp(cinode->lease_key, pSMB->LeaseKey,
+ 16))
+ continue;
+
+ cFYI(1, "lease key match, lease break 0x%d",
+ le32_to_cpu(pSMB->NewLeaseState));
+
+ smb2_set_oplock_level(cinode,
+ smb2_map_lease_to_oplock(pSMB->NewLeaseState));
+
+ if (pSMB->Flags &
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)
+ cfile->oplock_break_cancelled = false;
+ else
+ cfile->oplock_break_cancelled = true;
+
+ queue_work(system_nrt_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, "Can not process oplock break for non-existent connection");
+ return false;
+}
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
+{
+ struct smb2_hdr *buf = (struct smb2_hdr *)buffer;
+ struct oplock_break *pSMB = (struct oplock_break *)buf;
+ 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 (pSMB->hdr.Command != SMB2_OPLOCK_BREAK)
+ return false;
+
+ if (le16_to_cpu(pSMB->StructureSize) !=
+ smb2_rsp_struct_sizes[SMB2OPLOCK_BREAK]) {
+ if (le16_to_cpu(pSMB->StructureSize) == 44)
+ return smb2_is_valid_lease_break(buf, srv);
+ else
+ return false;
+ }
+
+ cFYI(1, "oplock level 0x%d", pSMB->OplockLevel);
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(tmp, &srv->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 (pSMB->PersistentFid != cfile->persist_fid)
+ continue;
+
+ if (pSMB->VolatileFid != cfile->volatile_fid)
+ continue;
+
+ cFYI(1, "file id match, oplock break");
+ cinode = CIFS_I(cfile->dentry->d_inode);
+
+ smb2_set_oplock_level(cinode,
+ pSMB->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+ cfile->oplock_break_cancelled = false;
+
+ queue_work(system_nrt_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/smb2pdu.c b/fs/cifs/smb2pdu.c
index bcc3513..25d7ac2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1088,7 +1088,6 @@ parse_lease_state(struct create_rsp *smb)
{
char *data_offset;
struct create_lease *lc;
- __u8 oplock = 0;
bool found = false;
data_offset = (char *)smb;
@@ -1111,19 +1110,9 @@ parse_lease_state(struct create_rsp *smb)
} while (le32_to_cpu(lc->ccontext.Next) != 0);
if (!found)
- return oplock;
-
- if (le32_to_cpu(lc->lcontext.LeaseState) & SMB2_LEASE_WRITE_CACHING) {
- if (le32_to_cpu(lc->lcontext.LeaseState) &
- SMB2_LEASE_HANDLE_CACHING)
- oplock = SMB2_OPLOCK_LEVEL_BATCH;
- else
- oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
- } else if (le32_to_cpu(lc->lcontext.LeaseState) &
- SMB2_LEASE_READ_CACHING)
- oplock = SMB2_OPLOCK_LEVEL_II;
+ return 0;
- return oplock;
+ return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
}
int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
@@ -1901,12 +1890,6 @@ qfsdev_exit:
return rc;
}
-int SMB2_oplock_break(struct cifs_tcon *ptcon, __u64 netfid)
-{
- /* BB FIXME BB */
- return -EOPNOTSUPP;
-}
-
int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
FILE_ALL_INFO_SMB2 *pdata)
@@ -2784,3 +2767,72 @@ int SMB2_lock(const int xid, struct cifs_tcon *tcon,
*/
return rc;
}
+
+int
+SMB2_oplock_break(const int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ __u8 oplock_level)
+{
+ int rc = 0, buf_type, status;
+ struct oplock_break *pSMB2 = NULL;
+ struct kvec iov[1];
+
+ cFYI(1, "SMB2_oplock_break");
+ rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &pSMB2);
+
+ if (rc)
+ return rc;
+
+ pSMB2->VolatileFid = volatile_fid;
+ pSMB2->PersistentFid = persistent_fid;
+ pSMB2->OplockLevel = oplock_level;
+
+ iov->iov_base = (char *)pSMB2;
+ iov->iov_len = get_rfc1002_length(pSMB2) + 4;
+
+ rc = smb2_sendrcv2(xid, tcon->ses, iov, 1, &buf_type, &status,
+ CIFS_STD_OP | CIFS_LOG_ERROR);
+ /* SMB2 buffer freed by function above */
+
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2OPLOCK_BREAK);
+ cFYI(1, "Send error in Oplock Break = %d", rc);
+ }
+
+ return rc;
+}
+
+int
+SMB2_lease_break(const int xid, struct cifs_tcon *tcon, __u8 *lease_key,
+ const __le32 lease_state)
+{
+ int rc = 0, buf_type, status;
+ struct lease_ack *pSMB2 = NULL;
+ struct kvec iov[1];
+
+ cFYI(1, "SMB2_lease_break");
+ rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &pSMB2);
+
+ if (rc)
+ return rc;
+
+ pSMB2->StructureSize = cpu_to_le16(36);
+ inc_rfc1001_len(&pSMB2->hdr, 12);
+
+ memcpy(pSMB2->LeaseKey, lease_key, 16);
+ pSMB2->LeaseState = lease_state;
+
+ iov->iov_base = (char *)pSMB2;
+ iov->iov_len = get_rfc1002_length(pSMB2) + 4;
+
+ rc = smb2_sendrcv2(xid, tcon->ses, iov, 1, &buf_type, &status,
+ CIFS_STD_OP | CIFS_LOG_ERROR);
+ /* SMB2 buffer freed by function above */
+
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2OPLOCK_BREAK);
+ cFYI(1, "Send error in Oplock Break = %d", rc);
+ }
+
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 6b8fd2f..3558057 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -741,6 +741,41 @@ struct ioctl_rsp {
__u8 Buffer[1];
} __attribute__((packed));
+struct oplock_break {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __u8 OplockLevel;
+ __u8 Reserved;
+ __le32 Reserved2;
+ __u64 PersistentFid;
+ __u64 VolatileFid;
+} __attribute__((packed));
+
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED cpu_to_le32(0x01)
+
+struct lease_break {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 44 */
+ __le16 Reserved;
+ __le32 Flags;
+ __u8 LeaseKey[16];
+ __le32 CurrentLeaseState;
+ __le32 NewLeaseState;
+ __le32 BreakReason;
+ __le32 AccessMaskHint;
+ __le32 ShareMaskHint;
+} __attribute__((packed));
+
+struct lease_ack {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 36 */
+ __le16 Reserved;
+ __le32 Flags;
+ __u8 LeaseKey[16];
+ __le32 LeaseState;
+ __le64 LeaseDuration;
+} __attribute__((packed));
+
/*****************************************************************
* All constants go here
*****************************************************************
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2408be1..490f922 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -200,7 +200,6 @@ extern int SMB2_QFS_attribute_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_QFS_device_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
-extern int SMB2_oplock_break(struct cifs_tcon *ptcon, __u64 netfid);
extern int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
FILE_ALL_INFO_SMB2 *pFindData);
@@ -252,6 +251,11 @@ extern int SMB2_set_ea_info(const int xid, struct cifs_tcon *tcon,
extern int SMB2_lock(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
u64 length, u64 offset, u32 lockFlags, int wait);
+extern int SMB2_oplock_break(const int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ const __u8 oplock_level);
+extern int SMB2_lease_break(const int xid, struct cifs_tcon *tcon,
+ __u8 *lease_key, const __le32 lease_state);
extern void DeleteMidQEntryComplex(struct mid_q_entry *midEntry);
extern int new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
unsigned int remaining_bytes, int request_type);
@@ -262,7 +266,11 @@ extern int smb2_wait_on_complex_mid(struct cifs_ses *ses,
unsigned long timeout,
unsigned long time_to_wait);
extern int smb2_readresp(struct TCP_Server_Info *server, bool cleanup);
-/* extern void smb2_oplock_break(struct work_struct *);
-extern bool is_smb2_oplock_break(struct smb2_hdr *, struct TCP_Server_Info *);*/
+extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
+extern __u8 smb2_map_lease_to_oplock(__le32 lease_state);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+ struct TCP_Server_Info *srv);
+extern void smb2_oplock_break(struct work_struct *work);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 46/53] CIFS: Add strictcache i/o for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (20 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 42/53] CIFS: Process oplocks for SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 51/53] CIFS: Change Makefile to support CONFIG_CIFS_SMB2 Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 52/53] CIFS: Add statfs support for SMB2 Pavel Shilovsky
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
---
fs/cifs/smb2file.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
fs/cifs/smb2proto.h | 4 ++++
2 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index a8cb423..6f9098a 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -57,8 +57,8 @@ const struct file_operations smb2_file_ops = {
const struct file_operations smb2_file_strict_ops = {
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = cifs_strict_readv,
- .aio_write = cifs_strict_writev,
+ .aio_read = smb2_strict_readv,
+ .aio_write = smb2_strict_writev,
.open = smb2_open,
.release = cifs_close,
.lock = cifs_lock,
@@ -114,8 +114,8 @@ const struct file_operations smb2_file_nobrl_ops = {
const struct file_operations smb2_file_strict_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = cifs_strict_readv,
- .aio_write = cifs_strict_writev,
+ .aio_read = smb2_strict_readv,
+ .aio_write = smb2_strict_writev,
.open = smb2_open,
.release = cifs_close,
.fsync = smb2_strict_fsync,
@@ -404,6 +404,26 @@ ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
return written;
}
+ssize_t smb2_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct inode *inode;
+
+ inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+ if (CIFS_I(inode)->clientCanCacheAll)
+ return generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+ /*
+ * In strict cache mode we need to write the data to the server exactly
+ * from the pos to pos+len-1 rather than flush all affected pages
+ * because it may cause a error with mandatory locks on these pages but
+ * not on the region from pos to ppos+len-1.
+ */
+
+ return smb2_user_writev(iocb, iov, nr_segs, pos);
+}
+
static int
smb2_iread_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
unsigned int *bytes_read, char **all_data, char **data_offset,
@@ -443,6 +463,28 @@ ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
return read;
}
+ssize_t smb2_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct inode *inode;
+
+ inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+ if (CIFS_I(inode)->clientCanCacheRead)
+ return generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+ /*
+ * In strict cache mode we need to read from the server all the time
+ * if we don't have level II oplock because the server can delay mtime
+ * change - so we can't make a decision about inode invalidating.
+ * And we can also fail with pagereading if there are mandatory locks
+ * on pages affected by this read but not on the region from pos to
+ * pos+len-1.
+ */
+
+ return smb2_user_readv(iocb, iov, nr_segs, pos);
+}
+
int
smb2_read_cb(int xid, struct cifsFileInfo *cfile, struct cifs_io_parms *parms,
unsigned int *bytes_read, char **buf, int *buf_type,
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 490f922..ef88f98 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -148,8 +148,12 @@ extern int smb2_fsync(struct file *file, loff_t start, loff_t end,
extern int smb2_open(struct inode *inode, struct file *file);
extern ssize_t smb2_user_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
+extern ssize_t smb2_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern ssize_t smb2_user_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
+extern ssize_t smb2_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern int smb2_writepages(struct address_space *mapping,
struct writeback_control *wbc);
extern int smb2_readpages(struct file *file, struct address_space *mapping,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 47/53] CIFS: Enable signing in SMB2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (22 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 45/53] CIFS: Process oplock/lease break for SMB2/2.1 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 48/53] CIFS: Process signing for SMB2_logoff Pavel Shilovsky
` (3 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Shirish Pargaonkar
From: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Enable signing in smb2. For smb2, hmac-sha256 is used instead
of hmac-md5 used for cifs/smb.
Signature field in smb2 header is 16 bytes instead of 8 bytes.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@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/smb2pdu.c | 39 +++++++++-
fs/cifs/smb2pdu.h | 3 +
fs/cifs/smb2proto.h | 4 +-
fs/cifs/smb2transport.c | 186 ++++++++++++++++++++++++++++++++++++++++++++--
7 files changed, 247 insertions(+), 18 deletions(-)
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index f66cc16..ed5452e 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 2cfb695..82e9d58 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -681,12 +681,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);
@@ -711,6 +716,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);
@@ -722,7 +734,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);
@@ -734,12 +745,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 56962a5..520fe75 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -131,8 +131,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/smb2pdu.c b/fs/cifs/smb2pdu.c
index 25d7ac2..ee7eec1 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -173,8 +173,7 @@ set_tcon_flags:
/* if (tcon->nocase)
buffer->Flags |= SMBFLG_CASELESS; */
if ((tcon->ses) && (tcon->ses->server))
- if (tcon->ses->server->sec_mode &
- SMB2_NEGOTIATE_SIGNING_REQUIRED)
+ if (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
buffer->Flags |= SMB2_FLAGS_SIGNED;
out:
smb->StructureSize2 = cpu_to_le16(parmsize);
@@ -661,6 +660,37 @@ SMB2_negotiate(unsigned int xid, struct cifs_ses *ses)
rc = -EIO;
goto neg_exit;
}
+
+ if ((sec_flags & CIFSSEC_MAY_SIGN) == 0) {
+ /* MUST_SIGN already includes the MAY_SIGN FLAG
+ so if this is zero it means that signing is disabled */
+ cFYI(1, "Signing disabled");
+ if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ cERROR(1, "Server requires "
+ "packet signing to be enabled in "
+ "/proc/fs/cifs/SecurityFlags.");
+ rc = -EOPNOTSUPP;
+ }
+ ses->server->sec_mode &=
+ ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+ } else if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
+ /* signing required */
+ cFYI(1, "Must sign - sec_flags 0x%x", sec_flags);
+ if ((ses->server->sec_mode & (SMB2_NEGOTIATE_SIGNING_ENABLED |
+ SMB2_NEGOTIATE_SIGNING_REQUIRED)) == 0) {
+ cERROR(1, "signing required but server lacks support");
+ rc = -EOPNOTSUPP;
+ } else
+ ses->server->sec_mode
+ |= SECMODE_SIGN_REQUIRED;
+ } else {
+ /* signing optional ie CIFSSEC_MAY_SIGN */
+ if ((ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
+ == 0)
+ ses->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,
&ses->server->sec_type);
@@ -933,7 +963,6 @@ SMB2_tcon(unsigned int xid, struct cifs_ses *ses,
pSMB2->hdr.smb2_buf_length =
cpu_to_be32(be32_to_cpu(pSMB2->hdr.smb2_buf_length)
- 1 /* pad */ + unc_path_len);
-
rc = smb2_sendrcv2(xid, ses, iov, 2, &resp_buftype /* ret */, &status,
CIFS_STD_OP | CIFS_LOG_ERROR);
cFYI(1, "tcon buftype %d rc %d status %d", resp_buftype, rc, status);
@@ -2476,9 +2505,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
/* result already set, check signature */
if (server->sec_mode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
-/* if (smb2_verify_signature(mid->resp_buf, server))
+ 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);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 3558057..d04e8b6 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1058,4 +1058,7 @@ struct symlink_reparse_data_buf {
char pathbuffer[1];
} __attribute__((packed));
+#define SMB2_SIGNATURE_SIZE (16)
+#define SMB2_NTLMV2_SESSKEY_SIZE (16)
+#define SMB2_HMACSHA256_SIZE (32)
#endif /* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index ef88f98..0425700 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -93,9 +93,7 @@ extern int smb2_sendrcv_blocking(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_hdr *out_buf,
int *pbytes_returned);
extern int sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *);
-/* BB FIXME - need to add SMB2's signing mechanism - not same as CIFS BB */
-/*extern int smb2_verify_signature(struct smb2_hdr *,
- const struct mac_key *mac_key);*/
+extern int smb2_verify_signature(struct smb2_hdr *, struct TCP_Server_Info *);
extern void smb2_echo_request(struct work_struct *work);
extern int smb2_demultiplex_thread(struct TCP_Server_Info *server);
extern int smb2_observe_thread(struct TCP_Server_Info *server);
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index adb701f..acdd0c6 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -37,6 +37,178 @@
extern mempool_t *smb2_mid_poolp;
+static int
+smb2_calc_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server,
+ char *signature)
+{
+ int rc;
+ unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+ unsigned char *sigptr = smb2_signature;
+
+ 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;
+ }
+
+ rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+ smb2_pdu->ProtocolId,
+ be32_to_cpu(smb2_pdu->smb2_buf_length));
+ 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_NTLMV2_SESSKEY_SIZE);
+
+ return rc;
+}
+
+static int
+smb2_calc_signature2(const struct kvec *iov, int n_vec,
+ struct TCP_Server_Info *server, struct smb2_hdr *smb2_pdu)
+{
+ int i, rc;
+ unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+ unsigned char *sigptr = smb2_signature;
+
+ 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_NTLMV2_SESSKEY_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, smb2_pdu);
+
+ return rc;
+}
+
+int
+smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server)
+{
+ unsigned int rc;
+ char server_response_sig[16];
+ char what_we_think_sig_should_be[20];
+
+ 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, 16);
+
+ memset(smb2_pdu->Signature, 0, 16);
+
+ rc = smb2_calc_signature(smb2_pdu, server, what_we_think_sig_should_be);
+
+ if (rc)
+ return rc;
+
+/* smb2_dump_mem("what we think it should be: ",
+ what_we_think_sig_should_be, 16); */
+
+ if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+ return -EACCES;
+ else
+ return 0;
+
+}
/*
* Set message id for the request. Should be called after wait_for_free_response
* and locking srv_mutex. iov array must have at least 1 element.
@@ -283,12 +455,8 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
/* convert the length into a more usable form */
if ((receive_len > 24) &&
(server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) {
- /* BB fixme */
- /*rc = smb2_verify_signature(mid->resp_buf,
- &ses->server->mac_signing_key);
- if (rc) {
+ if (smb2_verify_signature(mid->resp_buf, server))
cERROR(1, "Unexpected SMB signature");
- } */
}
return map_smb2_to_linux_error(mid->resp_buf, log_error);
@@ -353,12 +521,13 @@ smb2_sendrcv2(const unsigned int xid, struct cifs_ses *ses,
wake_up(&ses->server->request_q);
return rc;
}
- /* rc = sign_smb2(iov, n_vec, ses->server); BB
+
+ rc = smb2_sign_smb2(iov, n_vec, ses->server);
if (rc) {
mutex_unlock(&ses->server->srv_mutex);
cifs_small_buf_release(buf);
goto out;
- } */
+ }
midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(ses->server);
@@ -479,12 +648,11 @@ smb2_call_async(struct TCP_Server_Info *server, struct kvec *iov,
list_add_tail(&mid->qhead, &server->pending_mid_q);
spin_unlock(&GlobalMid_Lock);
-/* rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
+ rc = smb2_sign_smb2(iov, nvec, server);
if (rc) {
mutex_unlock(&server->srv_mutex);
goto out_err;
}
-*/
mid->receive = receive;
mid->callback = callback;
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 48/53] CIFS: Process signing for SMB2_logoff
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (23 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 47/53] CIFS: Enable signing in SMB2 Pavel Shilovsky
@ 2011-10-28 19:54 ` Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 49/53] CIFS: Introduce SMB2 Kconfig option Pavel Shilovsky
` (2 subsequent siblings)
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:54 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2pdu.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ee7eec1..4ce496a 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1035,6 +1035,8 @@ SMB2_logoff(const int xid, struct cifs_ses *ses)
/* since no tcon, smb2_init can not do this, so do here */
pSMB2->hdr.SessionId = ses->Suid;
+ if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+ pSMB2->hdr.Flags |= SMB2_FLAGS_SIGNED;
rc = smb2_sendrcv_norsp(xid, ses, &pSMB2->hdr,
CIFS_STD_OP | CIFS_LOG_ERROR);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 49/53] CIFS: Introduce SMB2 Kconfig option
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (24 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 48/53] CIFS: Process signing for SMB2_logoff Pavel Shilovsky
@ 2011-10-28 19:55 ` Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 50/53] CIFS: Introduce smb2 mounts as vers=2 Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 53/53] CIFS: Disable lock call for SMB2 since we don't support it Pavel Shilovsky
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:55 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
SMB2 is the followon to the CIFS (and SMB) protocols
and the default for Windows since Windows Vista, and also
now implemented by various non-Windows servers. SMB2
is more secure, has various performance advantages, including
larger i/o sizes, flow control, better caching model and more.
SMB2 also resolves some scalability limits in the cifs
protocol and adds many new features while being much
simpler (only a few dozen commands instead of hundreds)
and since the protocol is clearer it is
also more consistently implemented across servers
and thus easier to optimize.
After much discussion with Jeff Layton, Jeremy Allison
and others at Connectathon, we decided to move the smb2
code from a distinct .ko and fstype into distinct
C files that optionally build in cifs.ko. As a result
the Kconfig gets simpler.
To avoid destabilizing cifs, the smb2 code is going
to be moved into its own experimental CONFIG_CIFS_SMB2 ifdef
as it is merged and rereviewed. The changes to stable
cifs (builds with the smb2 ifdef off) are expected to be
fairly small.
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/Kconfig | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index ed5452e..c2ba4fb 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -160,3 +160,23 @@ config CIFS_NFSD_EXPORT
depends on CIFS && EXPERIMENTAL && BROKEN
help
Allows NFS server to export a CIFS mounted share (nfsd over cifs)
+
+config CIFS_SMB2
+ bool "SMB2 network file system support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && INET && BROKEN
+ select NLS
+ select KEYS
+ select FSCACHE
+ select DNS_RESOLVER
+
+ help
+ This enables experimental support for the SMB2 (Server Message Block
+ version 2) protocol. The SMB2 protocol is the successor to the
+ popular CIFS and SMB network file sharing protocols. SMB2 is the
+ native file sharing mechanism for recent versions of Windows
+ operating systems (since Vista). SMB2 enablement will eventually
+ allow users better performance, security and features, than would be
+ possible with cifs. Note that smb2 mount options also are simpler
+ (compared to cifs) due to protocol improvements.
+
+ Unless you are a developer or tester, say N.
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 50/53] CIFS: Introduce smb2 mounts as vers=2
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (25 preceding siblings ...)
2011-10-28 19:55 ` [PATCH v2 49/53] CIFS: Introduce SMB2 Kconfig option Pavel Shilovsky
@ 2011-10-28 19:55 ` Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 53/53] CIFS: Disable lock call for SMB2 since we don't support it Pavel Shilovsky
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:55 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
As with Linux nfs client, which uses "nfsvers=" or "vers=" to
indicate which protocol to use for mount, specifying
"vers=smb2" or "vers=2"
will force an smb2 mount. When vers is not specified cifs is used
ie "vers=cifs" or "vers=1"
We can eventually autonegotiate down from smb2 to cifs
when smb2 is stable enough to make it the default, but this
is for the future. At that time we could also implement a
"maxprotocol" mount option as smbclient and Samba have today,
but that would be premature until smb2 is stable.
Intially the smb2 Kconfig option will depend on "BROKEN"
until the merge is complete, and then be "EXPERIMENTAL"
When it is no longer experimental we can consider changing
the default protocol to attempt first.
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
---
fs/cifs/connect.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c8a94a4..cd1c85c 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1274,6 +1274,13 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
(strnicmp(value, "1", 1) == 0)) {
/* this is the default */
continue;
+ } else if ((strnicmp(value, "smb2", 4) == 0) ||
+ (strnicmp(value, "2", 1) == 0)) {
+#ifdef CONFIG_CIFS_SMB2
+ vol->use_smb2 = true;
+#else
+ cERROR(1, "smb2 support not enabled");
+#endif /* CONFIG_CIFS_SMB2 */
}
} else if ((strnicmp(data, "unc", 3) == 0)
|| (strnicmp(data, "target", 6) == 0)
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 51/53] CIFS: Change Makefile to support CONFIG_CIFS_SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (21 preceding siblings ...)
2011-10-28 19:54 ` [PATCH v2 46/53] CIFS: Add strictcache i/o " Pavel Shilovsky
@ 2011-10-28 19:55 ` Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 52/53] CIFS: Add statfs support for SMB2 Pavel Shilovsky
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:55 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/Makefile | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 005d524..00ec0a2 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -15,3 +15,7 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
+
+cifs-$(CONFIG_CIFS_SMB2) += smb2pdu.o smb2misc.o smb2sess.o smb2transport.o \
+ maperror.o smb2inode.o smb2dir.o smb2file.o \
+ smb2readdir.o smb2link.o
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 52/53] CIFS: Add statfs support for SMB2
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
` (22 preceding siblings ...)
2011-10-28 19:55 ` [PATCH v2 51/53] CIFS: Change Makefile to support CONFIG_CIFS_SMB2 Pavel Shilovsky
@ 2011-10-28 19:55 ` Pavel Shilovsky
23 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:55 UTC (permalink / raw)
To: linux-cifs; +Cc: linux-fsdevel
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
fs/cifs/cifsfs.c | 52 +++++++++++++++++++++++++++++++-------------------
fs/cifs/smb2glob.h | 2 +
fs/cifs/smb2pdu.c | 18 +++++++++++++++++
fs/cifs/smb2proto.h | 2 +
4 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3683384..844ea94 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -169,31 +169,14 @@ static void cifs_kill_sb(struct super_block *sb)
cifs_umount(cifs_sb);
}
-static int
-cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
+static void
+cifs_queryfs(int xid, struct cifs_tcon *tcon, 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;
- int xid;
-
- xid = GetXid();
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
- * maximum path.
- *
- * Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO.
- */
- buf->f_namelen = PATH_MAX;
- 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) &&
@@ -214,8 +197,37 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
*/
if (rc)
rc = SMBOldQFSInfo(xid, tcon, buf);
+}
+
+static int
+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 xid;
+
+ xid = GetXid();
+
+ /*
+ * PATH_MAX may be too long - it would presumably be total path,
+ * but note that some servers (includinng Samba 3) have a shorter
+ * maximum path.
+ *
+ * Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO.
+ */
+ buf->f_namelen = PATH_MAX;
+ buf->f_files = 0; /* undefined */
+ buf->f_ffree = 0; /* unlimited */
+
+#ifdef CONFIG_CIFS_SMB2
+ if (tcon->ses->server->is_smb2)
+ smb2_open_queryfs_close(xid, tcon, buf);
+ else
+#endif
+ cifs_queryfs(xid, tcon, buf);
- FreeXid(xid);
+ _FreeXid(xid);
return 0;
}
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 9e42f71..49634d4 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -25,6 +25,8 @@
#include <linux/workqueue.h>
#include "smb2pdu.h"
+#define SMB2_MAGIC_NUMBER 0xFE534D42
+
/*
* The sizes of various internal tables and strings
*/
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 4ce496a..dc73968 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1921,6 +1921,24 @@ qfsdev_exit:
return rc;
}
+void
+smb2_open_queryfs_close(int xid, struct cifs_tcon *tcon, struct kstatfs *buf)
+{
+ int rc;
+ u64 persist_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, &persist_fid, &volatile_fid,
+ FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock);
+ if (!rc) {
+ buf->f_type = SMB2_MAGIC_NUMBER;
+ SMB2_QFS_info(xid, tcon, persist_fid, volatile_fid,
+ buf);
+ SMB2_close(xid, tcon, persist_fid, volatile_fid);
+ }
+}
+
int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
FILE_ALL_INFO_SMB2 *pdata)
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 0425700..aa894cc 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -111,6 +111,8 @@ extern int smb2_open_op_close(int xid, struct cifs_tcon *tcon, __le16 *path,
__u32 desired_access, __u32 create_disposition,
__u32 file_attributes, __u32 create_options,
void *data, int command);
+extern void smb2_open_queryfs_close(int xid, struct cifs_tcon *tcon,
+ struct kstatfs *buf);
extern void smb2_set_ops(struct inode *inode);
extern bool smb2_is_size_safe_to_change(struct smb2_inode *smb2_ind,
__u64 end_of_file);
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH v2 53/53] CIFS: Disable lock call for SMB2 since we don't support it
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (26 preceding siblings ...)
2011-10-28 19:55 ` [PATCH v2 50/53] CIFS: Introduce smb2 mounts as vers=2 Pavel Shilovsky
@ 2011-10-28 19:55 ` Pavel Shilovsky
27 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-28 19:55 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/smb2file.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 6f9098a..2121b52 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -42,7 +42,7 @@ const struct file_operations smb2_file_ops = {
.aio_write = cifs_file_aio_write,
.open = smb2_open,
.release = cifs_close,
- .lock = cifs_lock,
+ /*.lock = cifs_lock,*/
.fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
@@ -61,7 +61,7 @@ const struct file_operations smb2_file_strict_ops = {
.aio_write = smb2_strict_writev,
.open = smb2_open,
.release = cifs_close,
- .lock = cifs_lock,
+ /*.lock = cifs_lock,*/
.fsync = smb2_strict_fsync,
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
@@ -81,7 +81,7 @@ const struct file_operations smb2_file_direct_ops = {
.aio_write = smb2_user_writev,
.open = smb2_open,
.release = cifs_close,
- .lock = cifs_lock,
+ /*.lock = cifs_lock, */
.fsync = smb2_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
--
1.7.1
^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session
[not found] ` <1319831704-3572-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-29 4:40 ` Jeff Layton
[not found] ` <20111029004046.2bf8e111-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
0 siblings, 1 reply; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 4:40 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, 28 Oct 2011 23:54:14 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Also set ses->is_smb2 when smb2 session initialized.
>
The commit message doesn't seem to be accurate. ses->is_smb2 is not
being set here (and doesn't seem to exist).
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifsglob.h | 1 +
> fs/cifs/connect.c | 16 +++++++++++++++-
> 2 files changed, 16 insertions(+), 1 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 6dfc7ef..179b784 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -172,6 +172,7 @@ struct smb_vol {
> mode_t file_mode;
> mode_t dir_mode;
> unsigned secFlg;
> + bool use_smb2:1; /* use SMB2 protocol rather that CIFS */
> bool retry:1;
> bool intr:1;
> bool setuids:1;
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index f70d87d..6743558 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -1,7 +1,7 @@
> /*
> * fs/cifs/connect.c
> *
> - * Copyright (C) International Business Machines Corp., 2002,2009
> + * Copyright (C) International Business Machines Corp., 2002,2011
> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> *
> * This library is free software; you can redistribute it and/or modify
> @@ -1760,6 +1760,14 @@ static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr,
> (struct sockaddr *)&vol->srcaddr))
> return 0;
>
> +#ifdef CONFIG_CIFS_SMB2
> + if ((server->is_smb2 == true) && (vol->use_smb2 == false))
> + return 0;
> +
> + if ((server->is_smb2 == false) && (vol->use_smb2 == true))
> + return 0;
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> if (!match_port(server, addr))
> return 0;
>
> @@ -1884,6 +1892,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>
> tcp_ses->noblocksnd = volume_info->noblocksnd;
> tcp_ses->noautotune = volume_info->noautotune;
> + /* BB should we set this unconditionally now, especially for SMB2 */
> tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
> atomic_set(&tcp_ses->inFlight, 0);
> init_waitqueue_head(&tcp_ses->response_q);
> @@ -1927,6 +1936,11 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
> goto out_err_crypto_release;
> }
>
> +#ifdef CONFIG_CIFS_SMB2
> + if (volume_info->use_smb2)
> + tcp_ses->is_smb2 = true;
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> /*
> * since we're in a cifs function already, we know that
> * this will succeed. No need for try_module_get().
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
2011-10-28 19:54 ` [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked Pavel Shilovsky
@ 2011-10-29 4:48 ` Jeff Layton
2011-10-29 5:12 ` Steve French
[not found] ` <20111029004814.41340503-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
0 siblings, 2 replies; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 4:48 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs, linux-fsdevel, Steve French
On Fri, 28 Oct 2011 23:54:13 +0400
Pavel Shilovsky <piastry@etersoft.ru> wrote:
> From: Steve French <sfrench@us.ibm.com>
>
> Adding SMB2 statistics requires changes to the way cifs handles stats.
> Since there are only 19 command codes, it also is easier to track by exact
> command code than it was for cifs. Turn the counters for protocol
> ops sent to be a union (one struct for cifs, one for smb2). While at it
> split out the functions which clear stats and prints stats into their own
> subfunctions so they are easy to read and don't go past 80 columns.
>
> Signed-off-by: Steve French <sfrench@us.ibm.com>
> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
> ---
> fs/cifs/cifs_debug.c | 146 ++++++++++++++++++++++++++++++-------------------
> fs/cifs/cifsglob.h | 56 ++++++++++++-------
> fs/cifs/cifssmb.c | 54 +++++++++---------
> fs/cifs/misc.c | 2 +-
> 4 files changed, 152 insertions(+), 106 deletions(-)
>
> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
> index 84e8c07..8ccdb15 100644
> --- a/fs/cifs/cifs_debug.c
> +++ b/fs/cifs/cifs_debug.c
> @@ -249,6 +249,55 @@ static const struct file_operations cifs_debug_data_proc_fops = {
> };
>
> #ifdef CONFIG_CIFS_STATS
> +
> +#ifdef CONFIG_CIFS_SMB2
> +static void smb2_clear_stats(struct cifs_tcon *tcon)
> +{
> + int i;
> +
> + atomic_set(&tcon->num_smbs_sent, 0);
> + for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
> + atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
> + atomic_set(&tcon->stats.smb2_stats.smb2_com_fail[i], 0);
> + }
> +}
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> +static void clear_cifs_stats(struct cifs_tcon *tcon)
> +{
> + atomic_set(&tcon->num_smbs_sent, 0);
> +
> +#ifdef CONFIG_CIFS_SMB2
> + if (tcon->ses->server->is_smb2) {
> + smb2_clear_stats(tcon);
> + return;
> + }
> +#endif /* CONFIG_CIFS_SMB2 */
> +
^^^^^^^^^^^^^
The above logic should be encapsulated in smb2_clear_stats, and that
function should just be a noop when CONFIG_CIFS_SMB2 is not set.
> + /* cifs specific statistics, not applicable to smb2 sessions */
> + atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
> + atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
> +}
> +
> static ssize_t cifs_stats_proc_write(struct file *file,
> const char __user *buffer, size_t count, loff_t *ppos)
> {
> @@ -279,25 +328,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
> tcon = list_entry(tmp3,
> struct cifs_tcon,
> tcon_list);
> - atomic_set(&tcon->num_smbs_sent, 0);
> - atomic_set(&tcon->num_writes, 0);
> - atomic_set(&tcon->num_reads, 0);
> - atomic_set(&tcon->num_oplock_brks, 0);
> - atomic_set(&tcon->num_opens, 0);
> - atomic_set(&tcon->num_posixopens, 0);
> - atomic_set(&tcon->num_posixmkdirs, 0);
> - atomic_set(&tcon->num_closes, 0);
> - atomic_set(&tcon->num_deletes, 0);
> - atomic_set(&tcon->num_mkdirs, 0);
> - atomic_set(&tcon->num_rmdirs, 0);
> - atomic_set(&tcon->num_renames, 0);
> - atomic_set(&tcon->num_t2renames, 0);
> - atomic_set(&tcon->num_ffirst, 0);
> - atomic_set(&tcon->num_fnext, 0);
> - atomic_set(&tcon->num_fclose, 0);
> - atomic_set(&tcon->num_hardlinks, 0);
> - atomic_set(&tcon->num_symlinks, 0);
> - atomic_set(&tcon->num_locks, 0);
> + clear_cifs_stats(tcon);
> }
> }
> }
> @@ -307,6 +338,44 @@ static ssize_t cifs_stats_proc_write(struct file *file,
> return count;
> }
>
> +static void cifs_stats_print(struct seq_file *m, struct cifs_tcon *tcon)
> +{
> + if (tcon->need_reconnect)
> + seq_puts(m, "\tDISCONNECTED ");
> + seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
> + atomic_read(&tcon->num_smbs_sent),
> + atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
> + seq_printf(m, "\nReads: %d Bytes: %lld",
> + atomic_read(&tcon->stats.cifs_stats.num_reads),
> + (long long)(tcon->bytes_read));
> + seq_printf(m, "\nWrites: %d Bytes: %lld",
> + atomic_read(&tcon->stats.cifs_stats.num_writes),
> + (long long)(tcon->bytes_written));
> + seq_printf(m, "\nFlushes: %d",
> + atomic_read(&tcon->stats.cifs_stats.num_flushes));
> + seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
> + atomic_read(&tcon->stats.cifs_stats.num_locks),
> + atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
> + atomic_read(&tcon->stats.cifs_stats.num_symlinks));
> + seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
> + atomic_read(&tcon->stats.cifs_stats.num_opens),
> + atomic_read(&tcon->stats.cifs_stats.num_closes),
> + atomic_read(&tcon->stats.cifs_stats.num_deletes));
> + seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
> + atomic_read(&tcon->stats.cifs_stats.num_posixopens),
> + atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
> + seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
> + atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
> + atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
> + seq_printf(m, "\nRenames: %d T2 Renames %d",
> + atomic_read(&tcon->stats.cifs_stats.num_renames),
> + atomic_read(&tcon->stats.cifs_stats.num_t2renames));
> + seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
> + atomic_read(&tcon->stats.cifs_stats.num_ffirst),
> + atomic_read(&tcon->stats.cifs_stats.num_fnext),
> + atomic_read(&tcon->stats.cifs_stats.num_fclose));
> +}
> +
> static int cifs_stats_proc_show(struct seq_file *m, void *v)
> {
> int i;
> @@ -354,44 +423,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
> tcon_list);
> i++;
> seq_printf(m, "\n%d) %s", i, tcon->treeName);
> - if (tcon->need_reconnect)
> - seq_puts(m, "\tDISCONNECTED ");
> - seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
> - atomic_read(&tcon->num_smbs_sent),
> - atomic_read(&tcon->num_oplock_brks));
> - seq_printf(m, "\nReads: %d Bytes: %lld",
> - atomic_read(&tcon->num_reads),
> - (long long)(tcon->bytes_read));
> - seq_printf(m, "\nWrites: %d Bytes: %lld",
> - atomic_read(&tcon->num_writes),
> - (long long)(tcon->bytes_written));
> - seq_printf(m, "\nFlushes: %d",
> - atomic_read(&tcon->num_flushes));
> - seq_printf(m, "\nLocks: %d HardLinks: %d "
> - "Symlinks: %d",
> - atomic_read(&tcon->num_locks),
> - atomic_read(&tcon->num_hardlinks),
> - atomic_read(&tcon->num_symlinks));
> - seq_printf(m, "\nOpens: %d Closes: %d "
> - "Deletes: %d",
> - atomic_read(&tcon->num_opens),
> - atomic_read(&tcon->num_closes),
> - atomic_read(&tcon->num_deletes));
> - seq_printf(m, "\nPosix Opens: %d "
> - "Posix Mkdirs: %d",
> - atomic_read(&tcon->num_posixopens),
> - atomic_read(&tcon->num_posixmkdirs));
> - seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
> - atomic_read(&tcon->num_mkdirs),
> - atomic_read(&tcon->num_rmdirs));
> - seq_printf(m, "\nRenames: %d T2 Renames %d",
> - atomic_read(&tcon->num_renames),
> - atomic_read(&tcon->num_t2renames));
> - seq_printf(m, "\nFindFirst: %d FNext %d "
> - "FClose %d",
> - atomic_read(&tcon->num_ffirst),
> - atomic_read(&tcon->num_fnext),
> - atomic_read(&tcon->num_fclose));
> + cifs_stats_print(m, tcon);
> }
> }
> }
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 4c38b04..6dfc7ef 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -292,6 +292,7 @@ struct TCP_Server_Info {
> bool sec_kerberos; /* supports plain Kerberos */
> bool sec_mskerberos; /* supports legacy MS Kerberos */
> bool large_buf; /* is current buffer large? */
> + bool is_smb2; /* smb2 not cifs protocol negotiated */
> struct delayed_work echo; /* echo ping workqueue job */
> struct kvec *iov; /* reusable kvec array for receives */
> unsigned int nr_iov; /* number of kvecs in array */
> @@ -392,6 +393,9 @@ struct cifs_ses {
> negotiate one of the older LANMAN dialects */
> #define CIFS_SES_LANMAN 8
> #define CIFS_SES_SMB2 16
> +
> +#define NUMBER_OF_SMB2_COMMANDS 0x0013
> +
> /*
> * there is one of these for each connection to a resource on a particular
> * session
> @@ -409,27 +413,37 @@ struct cifs_tcon {
> enum statusEnum tidStatus;
> #ifdef CONFIG_CIFS_STATS
> atomic_t num_smbs_sent;
> - atomic_t num_writes;
> - atomic_t num_reads;
> - atomic_t num_flushes;
> - atomic_t num_oplock_brks;
> - atomic_t num_opens;
> - atomic_t num_closes;
> - atomic_t num_deletes;
> - atomic_t num_mkdirs;
> - atomic_t num_posixopens;
> - atomic_t num_posixmkdirs;
> - atomic_t num_rmdirs;
> - atomic_t num_renames;
> - atomic_t num_t2renames;
> - atomic_t num_ffirst;
> - atomic_t num_fnext;
> - atomic_t num_fclose;
> - atomic_t num_hardlinks;
> - atomic_t num_symlinks;
> - atomic_t num_locks;
> - atomic_t num_acl_get;
> - atomic_t num_acl_set;
> + union {
> + struct {
> + atomic_t num_writes;
> + atomic_t num_reads;
> + atomic_t num_flushes;
> + atomic_t num_oplock_brks;
> + atomic_t num_opens;
> + atomic_t num_closes;
> + atomic_t num_deletes;
> + atomic_t num_mkdirs;
> + atomic_t num_posixopens;
> + atomic_t num_posixmkdirs;
> + atomic_t num_rmdirs;
> + atomic_t num_renames;
> + atomic_t num_t2renames;
> + atomic_t num_ffirst;
> + atomic_t num_fnext;
> + atomic_t num_fclose;
> + atomic_t num_hardlinks;
> + atomic_t num_symlinks;
> + atomic_t num_locks;
> + atomic_t num_acl_get;
> + atomic_t num_acl_set;
> + } cifs_stats;
> +#ifdef CONFIG_CIFS_SMB2
> + struct {
> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
> + } smb2_stats;
Is it really necessary to do this with atomics? Those can have
significant performance impact (TLB flushes, and we don't seem to need the
guarantees that they provide for simple counters like this. Perhaps
these should be switched to per-cpu variables or just plain ints?
> +#endif /* CONFIG CIFS_SMB2 */
> + } stats;
> #ifdef CONFIG_CIFS_STATS2
> unsigned long long time_writes;
> unsigned long long time_reads;
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index ea7b813..4e11051 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -867,7 +867,7 @@ PsxDelete:
> cFYI(1, "Posix delete returned %d", rc);
> cifs_buf_release(pSMB);
>
> - cifs_stats_inc(&tcon->num_deletes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
>
> if (rc == -EAGAIN)
> goto PsxDelete;
> @@ -909,7 +909,7 @@ DelFileRetry:
> pSMB->ByteCount = cpu_to_le16(name_len + 1);
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_deletes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
> if (rc)
> cFYI(1, "Error in RMFile = %d", rc);
>
> @@ -953,7 +953,7 @@ RmDirRetry:
> pSMB->ByteCount = cpu_to_le16(name_len + 1);
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_rmdirs);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
> if (rc)
> cFYI(1, "Error in RMDir = %d", rc);
>
> @@ -996,7 +996,7 @@ MkDirRetry:
> pSMB->ByteCount = cpu_to_le16(name_len + 1);
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_mkdirs);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
> if (rc)
> cFYI(1, "Error in Mkdir = %d", rc);
>
> @@ -1118,9 +1118,9 @@ psx_create_err:
> cifs_buf_release(pSMB);
>
> if (posix_flags & SMB_O_DIRECTORY)
> - cifs_stats_inc(&tcon->num_posixmkdirs);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
> else
> - cifs_stats_inc(&tcon->num_posixopens);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
>
> if (rc == -EAGAIN)
> goto PsxCreat;
> @@ -1241,7 +1241,7 @@ OldOpenRetry:
> /* long_op set to 1 to allow for oplock break timeouts */
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *)pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_opens);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
> if (rc) {
> cFYI(1, "Error in Open = %d", rc);
> } else {
> @@ -1354,7 +1354,7 @@ openRetry:
> /* long_op set to 1 to allow for oplock break timeouts */
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *)pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_opens);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
> if (rc) {
> cFYI(1, "Error in Open = %d", rc);
> } else {
> @@ -1728,7 +1728,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
> rdata, false);
>
> if (rc == 0)
> - cifs_stats_inc(&tcon->num_reads);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
>
> cifs_small_buf_release(smb);
> return rc;
> @@ -1796,7 +1796,7 @@ CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
> iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
> rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
> &resp_buf_type, CIFS_LOG_ERROR);
> - cifs_stats_inc(&tcon->num_reads);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
> pSMBr = (READ_RSP *)iov[0].iov_base;
> if (rc) {
> cERROR(1, "Send error in read = %d", rc);
> @@ -1948,7 +1948,7 @@ CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
> - cifs_stats_inc(&tcon->num_writes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
> if (rc) {
> cFYI(1, "Send error in write = %d", rc);
> } else {
> @@ -2197,7 +2197,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
> NULL, cifs_writev_callback, wdata, false);
>
> if (rc == 0)
> - cifs_stats_inc(&tcon->num_writes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
> else
> kref_put(&wdata->refcount, cifs_writedata_release);
>
> @@ -2287,7 +2287,7 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
>
> rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
> long_op);
> - cifs_stats_inc(&tcon->num_writes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
> if (rc) {
> cFYI(1, "Send error Write2 = %d", rc);
> } else if (resp_buf_type == 0) {
> @@ -2353,7 +2353,7 @@ int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
> iov[1].iov_base = (char *)buf;
> iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
>
> - cifs_stats_inc(&tcon->num_locks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
> rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
> if (rc)
> cFYI(1, "Send error in cifs_lockv = %d", rc);
> @@ -2422,7 +2422,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
> timeout);
> /* SMB buffer freed by function above */
> }
> - cifs_stats_inc(&tcon->num_locks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
> if (rc)
> cFYI(1, "Send error in Lock = %d", rc);
>
> @@ -2587,7 +2587,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
> pSMB->LastWriteTime = 0xFFFFFFFF;
> pSMB->ByteCount = 0;
> rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> - cifs_stats_inc(&tcon->num_closes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
> if (rc) {
> if (rc != -EINTR) {
> /* EINTR is expected when user ctl-c to kill app */
> @@ -2616,7 +2616,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
> pSMB->FileID = (__u16) smb_file_id;
> pSMB->ByteCount = 0;
> rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> - cifs_stats_inc(&tcon->num_flushes);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
> if (rc)
> cERROR(1, "Send error in Flush = %d", rc);
>
> @@ -2679,7 +2679,7 @@ renameRetry:
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_renames);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
> if (rc)
> cFYI(1, "Send error in rename = %d", rc);
>
> @@ -2758,7 +2758,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
> pSMB->ByteCount = cpu_to_le16(byte_count);
> rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&pTcon->num_t2renames);
> + cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
> if (rc)
> cFYI(1, "Send error in Rename (by file handle) = %d", rc);
>
> @@ -2915,7 +2915,7 @@ createSymLinkRetry:
> pSMB->ByteCount = cpu_to_le16(byte_count);
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_symlinks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
> if (rc)
> cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
>
> @@ -3001,7 +3001,7 @@ createHardLinkRetry:
> pSMB->ByteCount = cpu_to_le16(byte_count);
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_hardlinks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
> if (rc)
> cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
>
> @@ -3073,7 +3073,7 @@ winCreateHardLinkRetry:
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_hardlinks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
> if (rc)
> cFYI(1, "Send error in hard link (NT rename) = %d", rc);
>
> @@ -3490,7 +3490,7 @@ queryAclRetry:
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_acl_get);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
> if (rc) {
> cFYI(1, "Send error in Query POSIX ACL = %d", rc);
> } else {
> @@ -3801,7 +3801,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
>
> rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
> 0);
> - cifs_stats_inc(&tcon->num_acl_get);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
> if (rc) {
> cFYI(1, "Send error in QuerySecDesc = %d", rc);
> } else { /* decode response */
> @@ -4405,7 +4405,7 @@ findFirstRetry:
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_ffirst);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
>
> if (rc) {/* BB add logic to retry regular search if Unix search
> rejected unexpectedly by server */
> @@ -4532,7 +4532,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
>
> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> - cifs_stats_inc(&tcon->num_fnext);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
> if (rc) {
> if (rc == -EBADF) {
> psrch_inf->endOfSearch = true;
> @@ -4623,7 +4623,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
> if (rc)
> cERROR(1, "Send error in FindClose = %d", rc);
>
> - cifs_stats_inc(&tcon->num_fclose);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
>
> /* Since session is dead, search handle closed on server already */
> if (rc == -EAGAIN)
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index 703ef5c..1934575 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
> if (tcon->tid != buf->Tid)
> continue;
>
> - cifs_stats_inc(&tcon->num_oplock_brks);
> + cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
> spin_lock(&cifs_file_list_lock);
> list_for_each(tmp2, &tcon->openFileList) {
> netfile = list_entry(tmp2, struct cifsFileInfo,
--
Jeff Layton <jlayton@samba.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 01/53] CIFS: Update cifs global structures to handle smb2 sessions
[not found] ` <1319831704-3572-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-29 4:54 ` Jeff Layton
0 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 4:54 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, 28 Oct 2011 23:54:12 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> cifsglob.h defines the per socket structures
> smb2 could already use the per-smb socket structures,
> but to use the per-socket structures required additional
> optional fields. (Note that the tree connection
> structure differs substantially and will probably endup
> as a based tcon structure used by smb2 and cifs and a
> union for the stats.
>
> Also save whole smb2 dialect minor version - Jeff suggested
> that easier to handle future version updates if we treat
> the minor version in its native wire form rather than as
> series of booleans.
>
> Prepratory to merging more of the smb2 global routines
> 1) cleanup some unused structs and defines
> 2) add in externs for smb2 debugging routines
>
> smb2 needs to save off device_type on tcon and share_flags on tcon and
> session flags and subdialect on sessionsetup
>
> Acked-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
I don't remember acking this, but if I did, I'm rescinding it now. It
doesn't make any sense to add fields to structs that aren't being used
yet. You should only add fields to them as you need them, and those
changes should preferably be part of the patches that add the code that
uses those new fields.
I can't reasonably review this patch as adding these fields lacks any
context whatsoever.
> ---
> fs/cifs/TODO | 2 ++
> fs/cifs/cifs_debug.h | 12 +++++++++---
> fs/cifs/cifs_fs_sb.h | 4 +++-
> fs/cifs/cifsacl.h | 2 +-
> fs/cifs/cifsglob.h | 44 +++++++++++++++++++++++++++++++++-----------
> fs/cifs/cifspdu.h | 2 ++
> fs/cifs/cifssmb.c | 2 +-
> fs/cifs/sess.c | 2 +-
> 8 files changed, 52 insertions(+), 18 deletions(-)
>
> diff --git a/fs/cifs/TODO b/fs/cifs/TODO
> index 355abcd..2c68abc 100644
> --- a/fs/cifs/TODO
> +++ b/fs/cifs/TODO
> @@ -1,5 +1,7 @@
> Version 1.53 May 20, 2008
>
> +PUT IN WARNING FOR NTLMV2 becoming default
> +
> A Partial List of Missing Features
> ==================================
>
> diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
> index 8942b28..fec0743 100644
> --- a/fs/cifs/cifs_debug.h
> +++ b/fs/cifs/cifs_debug.h
> @@ -1,6 +1,6 @@
> /*
> *
> - * Copyright (c) International Business Machines Corp., 2000,2002
> + * Copyright (c) International Business Machines Corp., 2000,2011
> * Modified by Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> *
> * This program is free software; you can redistribute it and/or modify
> @@ -18,7 +18,7 @@
> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> *
> */
> -#define CIFS_DEBUG /* BB temporary */
> +#define CIFS_DEBUG /* remove to disable cifserror logging */
>
> #ifndef _H_CIFS_DEBUG
> #define _H_CIFS_DEBUG
> @@ -28,6 +28,9 @@ void cifs_dump_mem(char *label, void *data, int length);
> #define DBG2 2
> void cifs_dump_detail(struct smb_hdr *);
> void cifs_dump_mids(struct TCP_Server_Info *);
> +#ifdef CONFIG_CIFS_SMB2
> +void smb2_dump_detail(struct smb2_hdr *);
> +#endif /* CONFIG_CIFS_SMB2 */
> #else
> #define DBG2 0
> #endif
> @@ -37,12 +40,15 @@ void dump_smb(struct smb_hdr *, int);
> #define CIFS_RC 0x02
> #define CIFS_TIMER 0x04
>
> +#ifdef CONFIG_CIFS_SMB2
> +void dump_smb2(struct smb2_hdr *, int);
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> /*
> * debug ON
> * --------
> */
> #ifdef CIFS_DEBUG
> -
> /* information message: e.g., configuration, major event */
> extern int cifsFYI;
> #define cifsfyi(fmt, arg...) \
> diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
> index 500d658..8e6dd9a 100644
> --- a/fs/cifs/cifs_fs_sb.h
> +++ b/fs/cifs/cifs_fs_sb.h
> @@ -1,7 +1,7 @@
> /*
> * fs/cifs/cifs_fs_sb.h
> *
> - * Copyright (c) International Business Machines Corp., 2002,2004
> + * Copyright (c) International Business Machines Corp., 2002,2010
> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> *
> * This library is free software; you can redistribute it and/or modify
> @@ -24,10 +24,12 @@
>
> #define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
> #define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
> +/* SERVER_INUM is always set for SMB2 */
> #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
> #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
> #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
> #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
> +/* The following two are not supported for SMB2 */
> #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible*/
> #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
> #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
> diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
> index 5c902c7..ba9a9db 100644
> --- a/fs/cifs/cifsacl.h
> +++ b/fs/cifs/cifsacl.h
> @@ -1,7 +1,7 @@
> /*
> * fs/cifs/cifsacl.h
> *
> - * Copyright (c) International Business Machines Corp., 2007
> + * Copyright (c) International Business Machines Corp., 2007,2010
> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> *
> * This library is free software; you can redistribute it and/or modify
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 8238aa1..4c38b04 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1,7 +1,7 @@
> /*
> * fs/cifs/cifsglob.h
> *
> - * Copyright (C) International Business Machines Corp., 2002,2008
> + * Copyright (C) International Business Machines Corp., 2002,2011
> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> * Jeremy Allison (jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org)
> *
> @@ -259,7 +259,7 @@ struct TCP_Server_Info {
> struct mutex srv_mutex;
> struct task_struct *tsk;
> char server_GUID[16];
> - char sec_mode;
> + __u16 sec_mode;
> bool session_estab; /* mark when very first sess is established */
> u16 dialect; /* dialect index that server chose */
> enum securityEnum secType;
> @@ -305,6 +305,18 @@ struct TCP_Server_Info {
> atomic_t in_send; /* requests trying to send */
> atomic_t num_waiters; /* blocked waiting to get in sendrecv */
> #endif
> +#ifdef CONFIG_CIFS_SMB2
> + wait_queue_head_t read_q; /* used by readpages */
> + atomic_t active_readpage_req; /* used by readpages */
> + atomic_t resp_rdy; /* used by readpages and demultiplex */
> + __le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
> + struct task_struct *observe;
> + char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
> + __u64 current_smb2_mid; /* multiplex id - rotating counter */
> + __u8 speed; /* helps us identify if this is a slow link */
> + unsigned int max_read;
> + unsigned int max_write;
> +#endif /* CONFIG_CIFS_SMB2 */
> };
>
^^^^^^^^^^^^
Instead of dumping all of this stuff into the struct in an initial
patch, you should instead add these fields piecemeal, as you need them.
I have no way to tell whether this makes any sense since it lacks any
context with code that will use it.
> /*
> @@ -354,7 +366,7 @@ struct cifs_ses {
> char *serverOS; /* name of operating system underlying server */
> char *serverNOS; /* name of network operating system of server */
> char *serverDomain; /* security realm of server */
> - int Suid; /* remote smb uid */
> + __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;
> @@ -367,6 +379,9 @@ struct cifs_ses {
> struct session_key auth_key;
> struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
> bool need_reconnect:1; /* connection reset, uid now invalid */
> +#ifdef CONFIG_CIFS_SMB2
> + __u16 session_flags;
> +#endif /* CONFIG_CIFS_SMB2 */
> };
> /* no more than one of the following three session flags may be set */
> #define CIFS_SES_NT4 1
> @@ -376,6 +391,7 @@ 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
> +#define CIFS_SES_SMB2 16
> /*
> * there is one of these for each connection to a resource on a particular
> * session
> @@ -388,7 +404,7 @@ struct cifs_tcon {
> char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
> char *nativeFileSystem;
> char *password; /* for share-level security */
> - __u16 tid; /* The 2 byte tree id */
> + __u32 tid; /* The 4 byte tree id */
> __u16 Flags; /* optional support bits */
> enum statusEnum tidStatus;
> #ifdef CONFIG_CIFS_STATS
> @@ -436,6 +452,7 @@ struct cifs_tcon {
> FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
> FILE_SYSTEM_UNIX_INFO fsUnixInfo;
> bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
> + bool print:1; /* set if connection to printer share */
> bool retry:1;
> bool nocase:1;
> bool seal:1; /* transport encryption for this mounted share */
> @@ -444,6 +461,15 @@ struct cifs_tcon {
> bool local_lease:1; /* check leases (only) on local system not remote */
> bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
> bool need_reconnect:1; /* connection reset, tid now invalid */
> + bool bad_network_name:1;
> +#ifdef CONFIG_CIFS_SMB2
> + __u32 capabilities;
> + __u32 share_flags;
> + __u32 maximal_access;
> + __u32 vol_serial_number;
> + __le64 vol_create_time;
> + struct mutex tcon_mutex;
> +#endif /* CONFIG_CIFS_SMB2 */
> #ifdef CONFIG_CIFS_FSCACHE
> u64 resource_id; /* server resource id */
> struct fscache_cookie *fscache; /* cookie for share */
> @@ -802,6 +828,7 @@ struct cifs_fattr {
> struct timespec cf_atime;
> struct timespec cf_mtime;
> struct timespec cf_ctime;
> + u32 ea_size;
> };
>
> static inline void free_dfs_info_param(struct dfs_info3_param *param)
> @@ -833,6 +860,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
> #define MID_RETRY_NEEDED 8 /* session closed while this request out */
> #define MID_RESPONSE_MALFORMED 0x10
> #define MID_SHUTDOWN 0x20
> +#define MID_NO_RESPONSE_NEEDED 0x40
>
> /* Types of response buffer returned from SendReceive2 */
> #define CIFS_NO_BUFFER 0 /* Response buffer not returned */
> @@ -841,6 +869,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
> #define CIFS_IOVEC 4 /* array of response buffers */
>
> /* Type of Request to SendReceive2 */
> +#define CIFS_STD_OP 0
> #define CIFS_BLOCKING_OP 1 /* operation can block */
> #define CIFS_ASYNC_OP 2 /* do not wait for response */
> #define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */
> @@ -891,13 +920,6 @@ require use of the stronger protocol */
> #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
> #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
> #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
> -/*
> - *****************************************************************
> - * All constants go here
> - *****************************************************************
> - */
> -
> -#define UID_HASH (16)
>
> /*
> * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the
> diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
> index 3fb03e2..d1cfc81 100644
> --- a/fs/cifs/cifspdu.h
> +++ b/fs/cifs/cifspdu.h
> @@ -428,6 +428,8 @@ struct smb_hdr {
> __u8 WordCount;
> } __attribute__((packed));
>
> +struct smb2_hdr;
> +
> /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
> static inline void *
> BCC(struct smb_hdr *smb)
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 6600aa2..ea7b813 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -457,7 +457,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
> rc = -EOPNOTSUPP;
> goto neg_err_exit;
> }
> - server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
> + server->sec_mode = le16_to_cpu(rsp->SecurityMode);
> server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
> server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
> server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index c7d80e2..5b7c94f 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -895,7 +895,7 @@ ssetup_ntlmssp_authenticate:
> if (action & GUEST_LOGIN)
> cFYI(1, "Guest login"); /* BB mark SesInfo struct? */
> ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
> - cFYI(1, "UID = %d ", ses->Suid);
> + cFYI(1, "UID = %llu ", ses->Suid);
> /* response can have either 3 or 4 word count - Samba sends 3 */
> /* and lanman response is 3 */
> bytes_remaining = get_bcc(smb_buf);
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 04/53] CIFS: Do not try to dump cifs mids from smb2 sessions
[not found] ` <1319831704-3572-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-29 5:05 ` Jeff Layton
0 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 5:05 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, 28 Oct 2011 23:54:15 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Convert the debug routines in cifs_debug.c to recognize
> smb2 sessions and not try to dump invalid information on
> pending requests. Check the socket type to see if
> smb2. Move the printing of cifs specific debug information
> to a helper routine to make it clearer which type
> of information we are printing.
>
> cifs and smb2 both use the struct TCP_Server_Info to include information about
> the tcp socket connection to the server. The list of pending requests
> is one of the "per-socket" pieces of information. smb2 and cifs
> "mid" queue entries (multiplexed network requests, the active requests
> on the wire) differ. smb2 has async support in the protocol,
> as well as operation compounding and larger sizes (than cifs) for
> various fields related to pending requests) so it is important
> not to try to use the pending_mid_q for smb2 tcp sessions
> as if it were a pending cifs request. Most usage of the
> pending_mid_q is safe because it is in either cifs or smb2
> specific code, but this patch fixes the dumping of debug
> data so we don't dump cifs debug data for an smb2 session.
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifs_debug.c | 179 +++++++++++++++++++++++++++-----------------------
> 1 files changed, 98 insertions(+), 81 deletions(-)
>
> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
> index 8ccdb15..add9975 100644
> --- a/fs/cifs/cifs_debug.c
> +++ b/fs/cifs/cifs_debug.c
> @@ -72,7 +72,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
> struct list_head *tmp;
> struct mid_q_entry *mid_entry;
>
> - if (server == NULL)
> + if ((server == NULL) || (server->is_smb2))
> return;
>
This looks like a cargo-cult check. When on earth would the server ever
be NULL here? I think you can just get rid of the NULL check here.
> cERROR(1, "Dump pending requests:");
> @@ -105,16 +105,105 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
> #endif /* CONFIG_CIFS_DEBUG2 */
>
> #ifdef CONFIG_PROC_FS
> -static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
> +
> +static void dump_smb2_debug_info(int i, struct seq_file *m,
> + struct TCP_Server_Info *server)
> {
> - struct list_head *tmp1, *tmp2, *tmp3;
> + seq_printf(m, "dumping debug information for smb2 not supported yet\n");
> +}
> +
> +static void dump_cifs_debug_info(int i, struct seq_file *m,
> + struct TCP_Server_Info *server)
> +{
> + struct list_head *tmp2, *tmp3;
> struct mid_q_entry *mid_entry;
> - struct TCP_Server_Info *server;
> struct cifs_ses *ses;
> struct cifs_tcon *tcon;
> - int i, j;
> + int j;
> __u32 dev_type;
>
> +
> + list_for_each(tmp2, &server->smb_ses_list) {
> + ses = list_entry(tmp2, struct cifs_ses, smb_ses_list);
> + if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
> + (ses->serverNOS == NULL)) {
^^^^^^^
No need for the extra parenthesis around each of these.
> + seq_printf(m, "\n%d) entry for %s not fully "
> + "displayed\n\t", i, ses->serverName);
> + } else {
> + seq_printf(m,
> + "\n%d) Name: %s Domain: %s Uses: %d OS:"
> + " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
> + " session status: %d\t",
> + i, ses->serverName, ses->serverDomain,
> + ses->ses_count, ses->serverOS, ses->serverNOS,
> + ses->capabilities, ses->status);
> + }
> + seq_printf(m, "TCP status: %d\n\tLocal Users To "
> + "Server: %d SecMode: 0x%x Req On Wire: %d",
> + server->tcpStatus, server->srv_count,
> + server->sec_mode,
> + atomic_read(&server->inFlight));
> +
> +#ifdef CONFIG_CIFS_STATS2
> + seq_printf(m, " In Send: %d In MaxReq Wait: %d",
> + atomic_read(&server->in_send),
> + atomic_read(&server->num_waiters));
> +#endif
> +
> + seq_puts(m, "\n\tShares:");
> + j = 0;
> + list_for_each(tmp3, &ses->tcon_list) {
> + tcon = list_entry(tmp3, struct cifs_tcon, tcon_list);
> + ++j;
> + dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
> + seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
> + tcon->treeName, tcon->tc_count);
> + if (tcon->nativeFileSystem) {
> + seq_printf(m, "Type: %s ",
> + tcon->nativeFileSystem);
> + }
> + seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
> + "\nPathComponentMax: %d Status: 0x%d",
> + le32_to_cpu(
> + tcon->fsDevInfo.DeviceCharacteristics),
> + le32_to_cpu(tcon->fsAttrInfo.Attributes),
> + le32_to_cpu(
> + tcon->fsAttrInfo.MaxPathNameComponentLength),
> + tcon->tidStatus);
> + if (dev_type == FILE_DEVICE_DISK)
> + seq_puts(m, " type: DISK ");
> + else if (dev_type == FILE_DEVICE_CD_ROM)
> + seq_puts(m, " type: CDROM ");
> + else
> + seq_printf(m, " type: %d ", dev_type);
> +
The above would be better as:
seq_puts(m, "type: ");
switch(dev_type) {
...
}
> + if (tcon->need_reconnect)
> + seq_puts(m, "\tDISCONNECTED ");
> + seq_putc(m, '\n');
> + }
> +
> + seq_puts(m, "\n\tMIDs:\n");
> +
> + spin_lock(&GlobalMid_Lock);
> + list_for_each(tmp3, &server->pending_mid_q) {
> + mid_entry = list_entry(tmp3, struct mid_q_entry, qhead);
> + seq_printf(m, "\tState: %d com: %d pid:"
> + " %d cbdata: %p mid %d\n",
> + mid_entry->midState,
> + (int)mid_entry->command, mid_entry->pid,
> + mid_entry->callback_data,
> + mid_entry->mid);
> + }
> + spin_unlock(&GlobalMid_Lock);
> + }
> +}
> +
> +static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
> +{
> + struct list_head *tmp1;
> + struct TCP_Server_Info *server;
> + int i;
> +
> seq_puts(m,
> "Display Internal CIFS Data Structures for Debugging\n"
> "---------------------------------------------------\n");
> @@ -151,82 +240,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
> server = list_entry(tmp1, struct TCP_Server_Info,
> tcp_ses_list);
> i++;
> - list_for_each(tmp2, &server->smb_ses_list) {
> - ses = list_entry(tmp2, struct cifs_ses,
> - smb_ses_list);
> - if ((ses->serverDomain == NULL) ||
> - (ses->serverOS == NULL) ||
> - (ses->serverNOS == NULL)) {
> - seq_printf(m, "\n%d) entry for %s not fully "
> - "displayed\n\t", i, ses->serverName);
> - } else {
> - seq_printf(m,
> - "\n%d) Name: %s Domain: %s Uses: %d OS:"
> - " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
> - " session status: %d\t",
> - i, ses->serverName, ses->serverDomain,
> - ses->ses_count, ses->serverOS, ses->serverNOS,
> - ses->capabilities, ses->status);
> - }
> - seq_printf(m, "TCP status: %d\n\tLocal Users To "
> - "Server: %d SecMode: 0x%x Req On Wire: %d",
> - server->tcpStatus, server->srv_count,
> - server->sec_mode,
> - atomic_read(&server->inFlight));
> -
> -#ifdef CONFIG_CIFS_STATS2
> - seq_printf(m, " In Send: %d In MaxReq Wait: %d",
> - atomic_read(&server->in_send),
> - atomic_read(&server->num_waiters));
> -#endif
> -
> - seq_puts(m, "\n\tShares:");
> - j = 0;
> - list_for_each(tmp3, &ses->tcon_list) {
> - tcon = list_entry(tmp3, struct cifs_tcon,
> - tcon_list);
> - ++j;
> - dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
> - seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
> - tcon->treeName, tcon->tc_count);
> - if (tcon->nativeFileSystem) {
> - seq_printf(m, "Type: %s ",
> - tcon->nativeFileSystem);
> - }
> - seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
> - "\nPathComponentMax: %d Status: 0x%d",
> - le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
> - le32_to_cpu(tcon->fsAttrInfo.Attributes),
> - le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
> - tcon->tidStatus);
> - if (dev_type == FILE_DEVICE_DISK)
> - seq_puts(m, " type: DISK ");
> - else if (dev_type == FILE_DEVICE_CD_ROM)
> - seq_puts(m, " type: CDROM ");
> - else
> - seq_printf(m, " type: %d ", dev_type);
> -
> - if (tcon->need_reconnect)
> - seq_puts(m, "\tDISCONNECTED ");
> - seq_putc(m, '\n');
> - }
> -
> - seq_puts(m, "\n\tMIDs:\n");
> -
> - spin_lock(&GlobalMid_Lock);
> - list_for_each(tmp3, &server->pending_mid_q) {
> - mid_entry = list_entry(tmp3, struct mid_q_entry,
> - qhead);
> - seq_printf(m, "\tState: %d com: %d pid:"
> - " %d cbdata: %p mid %d\n",
> - mid_entry->midState,
> - (int)mid_entry->command,
> - mid_entry->pid,
> - mid_entry->callback_data,
> - mid_entry->mid);
> - }
> - spin_unlock(&GlobalMid_Lock);
> - }
> + if (server->is_smb2)
> + dump_smb2_debug_info(i, m, server);
> + else
> + dump_cifs_debug_info(i, m, server);
> }
> spin_unlock(&cifs_tcp_ses_lock);
> seq_putc(m, '\n');
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
2011-10-29 4:48 ` Jeff Layton
@ 2011-10-29 5:12 ` Steve French
[not found] ` <CAH2r5mtpckA75LEAynsPLVsPfr7U0wnYAyZ1uKeK2VU9F1CGeQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
[not found] ` <20111029004814.41340503-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
1 sibling, 1 reply; 75+ messages in thread
From: Steve French @ 2011-10-29 5:12 UTC (permalink / raw)
To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs, linux-fsdevel, Steve French
On Fri, Oct 28, 2011 at 11:48 PM, Jeff Layton <jlayton@samba.org> wrote:
> On Fri, 28 Oct 2011 23:54:13 +0400
> Pavel Shilovsky <piastry@etersoft.ru> wrote:
>
>> From: Steve French <sfrench@us.ibm.com>
>>
>> Adding SMB2 statistics requires changes to the way cifs handles stats.
>> Since there are only 19 command codes, it also is easier to track by exact
>> command code than it was for cifs. Turn the counters for protocol
>> ops sent to be a union (one struct for cifs, one for smb2). While at it
>> split out the functions which clear stats and prints stats into their own
>> subfunctions so they are easy to read and don't go past 80 columns.
>>
>> Signed-off-by: Steve French <sfrench@us.ibm.com>
>> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
>> ---
>> fs/cifs/cifs_debug.c | 146 ++++++++++++++++++++++++++++++-------------------
>> fs/cifs/cifsglob.h | 56 ++++++++++++-------
>> fs/cifs/cifssmb.c | 54 +++++++++---------
>> fs/cifs/misc.c | 2 +-
>> 4 files changed, 152 insertions(+), 106 deletions(-)
>>
>> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
>> index 84e8c07..8ccdb15 100644
>> --- a/fs/cifs/cifs_debug.c
>> +++ b/fs/cifs/cifs_debug.c
>> @@ -249,6 +249,55 @@ static const struct file_operations cifs_debug_data_proc_fops = {
>> };
>>
>> #ifdef CONFIG_CIFS_STATS
>> +
>> +#ifdef CONFIG_CIFS_SMB2
>> +static void smb2_clear_stats(struct cifs_tcon *tcon)
>> +{
>> + int i;
>> +
>> + atomic_set(&tcon->num_smbs_sent, 0);
>> + for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
>> + atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
>> + atomic_set(&tcon->stats.smb2_stats.smb2_com_fail[i], 0);
>> + }
>> +}
>> +#endif /* CONFIG_CIFS_SMB2 */
>> +
>> +static void clear_cifs_stats(struct cifs_tcon *tcon)
>> +{
>> + atomic_set(&tcon->num_smbs_sent, 0);
>> +
>> +#ifdef CONFIG_CIFS_SMB2
>> + if (tcon->ses->server->is_smb2) {
>> + smb2_clear_stats(tcon);
>> + return;
>> + }
>> +#endif /* CONFIG_CIFS_SMB2 */
>> +
>
> ^^^^^^^^^^^^^
> The above logic should be encapsulated in smb2_clear_stats, and that
> function should just be a noop when CONFIG_CIFS_SMB2 is not set.
makes sense - could be easier to read your way
>> + /* cifs specific statistics, not applicable to smb2 sessions */
>> + atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
>> + atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
>> +}
>> +
>> static ssize_t cifs_stats_proc_write(struct file *file,
>> const char __user *buffer, size_t count, loff_t *ppos)
>> {
>> @@ -279,25 +328,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
>> tcon = list_entry(tmp3,
>> struct cifs_tcon,
>> tcon_list);
>> - atomic_set(&tcon->num_smbs_sent, 0);
>> - atomic_set(&tcon->num_writes, 0);
>> - atomic_set(&tcon->num_reads, 0);
>> - atomic_set(&tcon->num_oplock_brks, 0);
>> - atomic_set(&tcon->num_opens, 0);
>> - atomic_set(&tcon->num_posixopens, 0);
>> - atomic_set(&tcon->num_posixmkdirs, 0);
>> - atomic_set(&tcon->num_closes, 0);
>> - atomic_set(&tcon->num_deletes, 0);
>> - atomic_set(&tcon->num_mkdirs, 0);
>> - atomic_set(&tcon->num_rmdirs, 0);
>> - atomic_set(&tcon->num_renames, 0);
>> - atomic_set(&tcon->num_t2renames, 0);
>> - atomic_set(&tcon->num_ffirst, 0);
>> - atomic_set(&tcon->num_fnext, 0);
>> - atomic_set(&tcon->num_fclose, 0);
>> - atomic_set(&tcon->num_hardlinks, 0);
>> - atomic_set(&tcon->num_symlinks, 0);
>> - atomic_set(&tcon->num_locks, 0);
>> + clear_cifs_stats(tcon);
>> }
>> }
>> }
>> @@ -307,6 +338,44 @@ static ssize_t cifs_stats_proc_write(struct file *file,
>> return count;
>> }
>>
>> +static void cifs_stats_print(struct seq_file *m, struct cifs_tcon *tcon)
>> +{
>> + if (tcon->need_reconnect)
>> + seq_puts(m, "\tDISCONNECTED ");
>> + seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
>> + atomic_read(&tcon->num_smbs_sent),
>> + atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
>> + seq_printf(m, "\nReads: %d Bytes: %lld",
>> + atomic_read(&tcon->stats.cifs_stats.num_reads),
>> + (long long)(tcon->bytes_read));
>> + seq_printf(m, "\nWrites: %d Bytes: %lld",
>> + atomic_read(&tcon->stats.cifs_stats.num_writes),
>> + (long long)(tcon->bytes_written));
>> + seq_printf(m, "\nFlushes: %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_flushes));
>> + seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_locks),
>> + atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
>> + atomic_read(&tcon->stats.cifs_stats.num_symlinks));
>> + seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_opens),
>> + atomic_read(&tcon->stats.cifs_stats.num_closes),
>> + atomic_read(&tcon->stats.cifs_stats.num_deletes));
>> + seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_posixopens),
>> + atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
>> + seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
>> + atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
>> + seq_printf(m, "\nRenames: %d T2 Renames %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_renames),
>> + atomic_read(&tcon->stats.cifs_stats.num_t2renames));
>> + seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
>> + atomic_read(&tcon->stats.cifs_stats.num_ffirst),
>> + atomic_read(&tcon->stats.cifs_stats.num_fnext),
>> + atomic_read(&tcon->stats.cifs_stats.num_fclose));
>> +}
>> +
>> static int cifs_stats_proc_show(struct seq_file *m, void *v)
>> {
>> int i;
>> @@ -354,44 +423,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
>> tcon_list);
>> i++;
>> seq_printf(m, "\n%d) %s", i, tcon->treeName);
>> - if (tcon->need_reconnect)
>> - seq_puts(m, "\tDISCONNECTED ");
>> - seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
>> - atomic_read(&tcon->num_smbs_sent),
>> - atomic_read(&tcon->num_oplock_brks));
>> - seq_printf(m, "\nReads: %d Bytes: %lld",
>> - atomic_read(&tcon->num_reads),
>> - (long long)(tcon->bytes_read));
>> - seq_printf(m, "\nWrites: %d Bytes: %lld",
>> - atomic_read(&tcon->num_writes),
>> - (long long)(tcon->bytes_written));
>> - seq_printf(m, "\nFlushes: %d",
>> - atomic_read(&tcon->num_flushes));
>> - seq_printf(m, "\nLocks: %d HardLinks: %d "
>> - "Symlinks: %d",
>> - atomic_read(&tcon->num_locks),
>> - atomic_read(&tcon->num_hardlinks),
>> - atomic_read(&tcon->num_symlinks));
>> - seq_printf(m, "\nOpens: %d Closes: %d "
>> - "Deletes: %d",
>> - atomic_read(&tcon->num_opens),
>> - atomic_read(&tcon->num_closes),
>> - atomic_read(&tcon->num_deletes));
>> - seq_printf(m, "\nPosix Opens: %d "
>> - "Posix Mkdirs: %d",
>> - atomic_read(&tcon->num_posixopens),
>> - atomic_read(&tcon->num_posixmkdirs));
>> - seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
>> - atomic_read(&tcon->num_mkdirs),
>> - atomic_read(&tcon->num_rmdirs));
>> - seq_printf(m, "\nRenames: %d T2 Renames %d",
>> - atomic_read(&tcon->num_renames),
>> - atomic_read(&tcon->num_t2renames));
>> - seq_printf(m, "\nFindFirst: %d FNext %d "
>> - "FClose %d",
>> - atomic_read(&tcon->num_ffirst),
>> - atomic_read(&tcon->num_fnext),
>> - atomic_read(&tcon->num_fclose));
>> + cifs_stats_print(m, tcon);
>> }
>> }
>> }
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 4c38b04..6dfc7ef 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -292,6 +292,7 @@ struct TCP_Server_Info {
>> bool sec_kerberos; /* supports plain Kerberos */
>> bool sec_mskerberos; /* supports legacy MS Kerberos */
>> bool large_buf; /* is current buffer large? */
>> + bool is_smb2; /* smb2 not cifs protocol negotiated */
>> struct delayed_work echo; /* echo ping workqueue job */
>> struct kvec *iov; /* reusable kvec array for receives */
>> unsigned int nr_iov; /* number of kvecs in array */
>> @@ -392,6 +393,9 @@ struct cifs_ses {
>> negotiate one of the older LANMAN dialects */
>> #define CIFS_SES_LANMAN 8
>> #define CIFS_SES_SMB2 16
>> +
>> +#define NUMBER_OF_SMB2_COMMANDS 0x0013
>> +
>> /*
>> * there is one of these for each connection to a resource on a particular
>> * session
>> @@ -409,27 +413,37 @@ struct cifs_tcon {
>> enum statusEnum tidStatus;
>> #ifdef CONFIG_CIFS_STATS
>> atomic_t num_smbs_sent;
>> - atomic_t num_writes;
>> - atomic_t num_reads;
>> - atomic_t num_flushes;
>> - atomic_t num_oplock_brks;
>> - atomic_t num_opens;
>> - atomic_t num_closes;
>> - atomic_t num_deletes;
>> - atomic_t num_mkdirs;
>> - atomic_t num_posixopens;
>> - atomic_t num_posixmkdirs;
>> - atomic_t num_rmdirs;
>> - atomic_t num_renames;
>> - atomic_t num_t2renames;
>> - atomic_t num_ffirst;
>> - atomic_t num_fnext;
>> - atomic_t num_fclose;
>> - atomic_t num_hardlinks;
>> - atomic_t num_symlinks;
>> - atomic_t num_locks;
>> - atomic_t num_acl_get;
>> - atomic_t num_acl_set;
>> + union {
>> + struct {
>> + atomic_t num_writes;
>> + atomic_t num_reads;
>> + atomic_t num_flushes;
>> + atomic_t num_oplock_brks;
>> + atomic_t num_opens;
>> + atomic_t num_closes;
>> + atomic_t num_deletes;
>> + atomic_t num_mkdirs;
>> + atomic_t num_posixopens;
>> + atomic_t num_posixmkdirs;
>> + atomic_t num_rmdirs;
>> + atomic_t num_renames;
>> + atomic_t num_t2renames;
>> + atomic_t num_ffirst;
>> + atomic_t num_fnext;
>> + atomic_t num_fclose;
>> + atomic_t num_hardlinks;
>> + atomic_t num_symlinks;
>> + atomic_t num_locks;
>> + atomic_t num_acl_get;
>> + atomic_t num_acl_set;
>> + } cifs_stats;
>> +#ifdef CONFIG_CIFS_SMB2
>> + struct {
>> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
>> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
>> + } smb2_stats;
>
> Is it really necessary to do this with atomics? Those can have
> significant performance impact (TLB flushes, and we don't seem to need the
> guarantees that they provide for simple counters like this. Perhaps
> these should be switched to per-cpu variables or just plain ints?
presumably there is precedent for use of atomics rather than
wrapping updates to these in a mutex - if they are just int
would we have a case where the two overlapping updates could
badly corrupt the value?
--
Thanks,
Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
[not found] ` <CAH2r5mtpckA75LEAynsPLVsPfr7U0wnYAyZ1uKeK2VU9F1CGeQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-10-29 5:32 ` Jeff Layton
0 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 5:32 UTC (permalink / raw)
To: Steve French
Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Sat, 29 Oct 2011 00:12:45 -0500
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Fri, Oct 28, 2011 at 11:48 PM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> > On Fri, 28 Oct 2011 23:54:13 +0400
> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >
> >> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >>
> >> Adding SMB2 statistics requires changes to the way cifs handles stats.
> >> Since there are only 19 command codes, it also is easier to track by exact
> >> command code than it was for cifs. Turn the counters for protocol
> >> ops sent to be a union (one struct for cifs, one for smb2). While at it
> >> split out the functions which clear stats and prints stats into their own
> >> subfunctions so they are easy to read and don't go past 80 columns.
> >>
> >> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >> ---
> >> fs/cifs/cifs_debug.c | 146 ++++++++++++++++++++++++++++++-------------------
> >> fs/cifs/cifsglob.h | 56 ++++++++++++-------
> >> fs/cifs/cifssmb.c | 54 +++++++++---------
> >> fs/cifs/misc.c | 2 +-
> >> 4 files changed, 152 insertions(+), 106 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
> >> index 84e8c07..8ccdb15 100644
> >> --- a/fs/cifs/cifs_debug.c
> >> +++ b/fs/cifs/cifs_debug.c
> >> @@ -249,6 +249,55 @@ static const struct file_operations cifs_debug_data_proc_fops = {
> >> };
> >>
> >> #ifdef CONFIG_CIFS_STATS
> >> +
> >> +#ifdef CONFIG_CIFS_SMB2
> >> +static void smb2_clear_stats(struct cifs_tcon *tcon)
> >> +{
> >> + int i;
> >> +
> >> + atomic_set(&tcon->num_smbs_sent, 0);
> >> + for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
> >> + atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
> >> + atomic_set(&tcon->stats.smb2_stats.smb2_com_fail[i], 0);
> >> + }
> >> +}
> >> +#endif /* CONFIG_CIFS_SMB2 */
> >> +
> >> +static void clear_cifs_stats(struct cifs_tcon *tcon)
> >> +{
> >> + atomic_set(&tcon->num_smbs_sent, 0);
> >> +
> >> +#ifdef CONFIG_CIFS_SMB2
> >> + if (tcon->ses->server->is_smb2) {
> >> + smb2_clear_stats(tcon);
> >> + return;
> >> + }
> >> +#endif /* CONFIG_CIFS_SMB2 */
> >> +
> >
> > ^^^^^^^^^^^^^
> > The above logic should be encapsulated in smb2_clear_stats, and that
> > function should just be a noop when CONFIG_CIFS_SMB2 is not set.
>
> makes sense - could be easier to read your way
>
>
> >> + /* cifs specific statistics, not applicable to smb2 sessions */
> >> + atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
> >> + atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
> >> +}
> >> +
> >> static ssize_t cifs_stats_proc_write(struct file *file,
> >> const char __user *buffer, size_t count, loff_t *ppos)
> >> {
> >> @@ -279,25 +328,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
> >> tcon = list_entry(tmp3,
> >> struct cifs_tcon,
> >> tcon_list);
> >> - atomic_set(&tcon->num_smbs_sent, 0);
> >> - atomic_set(&tcon->num_writes, 0);
> >> - atomic_set(&tcon->num_reads, 0);
> >> - atomic_set(&tcon->num_oplock_brks, 0);
> >> - atomic_set(&tcon->num_opens, 0);
> >> - atomic_set(&tcon->num_posixopens, 0);
> >> - atomic_set(&tcon->num_posixmkdirs, 0);
> >> - atomic_set(&tcon->num_closes, 0);
> >> - atomic_set(&tcon->num_deletes, 0);
> >> - atomic_set(&tcon->num_mkdirs, 0);
> >> - atomic_set(&tcon->num_rmdirs, 0);
> >> - atomic_set(&tcon->num_renames, 0);
> >> - atomic_set(&tcon->num_t2renames, 0);
> >> - atomic_set(&tcon->num_ffirst, 0);
> >> - atomic_set(&tcon->num_fnext, 0);
> >> - atomic_set(&tcon->num_fclose, 0);
> >> - atomic_set(&tcon->num_hardlinks, 0);
> >> - atomic_set(&tcon->num_symlinks, 0);
> >> - atomic_set(&tcon->num_locks, 0);
> >> + clear_cifs_stats(tcon);
> >> }
> >> }
> >> }
> >> @@ -307,6 +338,44 @@ static ssize_t cifs_stats_proc_write(struct file *file,
> >> return count;
> >> }
> >>
> >> +static void cifs_stats_print(struct seq_file *m, struct cifs_tcon *tcon)
> >> +{
> >> + if (tcon->need_reconnect)
> >> + seq_puts(m, "\tDISCONNECTED ");
> >> + seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
> >> + atomic_read(&tcon->num_smbs_sent),
> >> + atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
> >> + seq_printf(m, "\nReads: %d Bytes: %lld",
> >> + atomic_read(&tcon->stats.cifs_stats.num_reads),
> >> + (long long)(tcon->bytes_read));
> >> + seq_printf(m, "\nWrites: %d Bytes: %lld",
> >> + atomic_read(&tcon->stats.cifs_stats.num_writes),
> >> + (long long)(tcon->bytes_written));
> >> + seq_printf(m, "\nFlushes: %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_flushes));
> >> + seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_locks),
> >> + atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
> >> + atomic_read(&tcon->stats.cifs_stats.num_symlinks));
> >> + seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_opens),
> >> + atomic_read(&tcon->stats.cifs_stats.num_closes),
> >> + atomic_read(&tcon->stats.cifs_stats.num_deletes));
> >> + seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_posixopens),
> >> + atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
> >> + seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
> >> + atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
> >> + seq_printf(m, "\nRenames: %d T2 Renames %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_renames),
> >> + atomic_read(&tcon->stats.cifs_stats.num_t2renames));
> >> + seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
> >> + atomic_read(&tcon->stats.cifs_stats.num_ffirst),
> >> + atomic_read(&tcon->stats.cifs_stats.num_fnext),
> >> + atomic_read(&tcon->stats.cifs_stats.num_fclose));
> >> +}
> >> +
> >> static int cifs_stats_proc_show(struct seq_file *m, void *v)
> >> {
> >> int i;
> >> @@ -354,44 +423,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
> >> tcon_list);
> >> i++;
> >> seq_printf(m, "\n%d) %s", i, tcon->treeName);
> >> - if (tcon->need_reconnect)
> >> - seq_puts(m, "\tDISCONNECTED ");
> >> - seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
> >> - atomic_read(&tcon->num_smbs_sent),
> >> - atomic_read(&tcon->num_oplock_brks));
> >> - seq_printf(m, "\nReads: %d Bytes: %lld",
> >> - atomic_read(&tcon->num_reads),
> >> - (long long)(tcon->bytes_read));
> >> - seq_printf(m, "\nWrites: %d Bytes: %lld",
> >> - atomic_read(&tcon->num_writes),
> >> - (long long)(tcon->bytes_written));
> >> - seq_printf(m, "\nFlushes: %d",
> >> - atomic_read(&tcon->num_flushes));
> >> - seq_printf(m, "\nLocks: %d HardLinks: %d "
> >> - "Symlinks: %d",
> >> - atomic_read(&tcon->num_locks),
> >> - atomic_read(&tcon->num_hardlinks),
> >> - atomic_read(&tcon->num_symlinks));
> >> - seq_printf(m, "\nOpens: %d Closes: %d "
> >> - "Deletes: %d",
> >> - atomic_read(&tcon->num_opens),
> >> - atomic_read(&tcon->num_closes),
> >> - atomic_read(&tcon->num_deletes));
> >> - seq_printf(m, "\nPosix Opens: %d "
> >> - "Posix Mkdirs: %d",
> >> - atomic_read(&tcon->num_posixopens),
> >> - atomic_read(&tcon->num_posixmkdirs));
> >> - seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
> >> - atomic_read(&tcon->num_mkdirs),
> >> - atomic_read(&tcon->num_rmdirs));
> >> - seq_printf(m, "\nRenames: %d T2 Renames %d",
> >> - atomic_read(&tcon->num_renames),
> >> - atomic_read(&tcon->num_t2renames));
> >> - seq_printf(m, "\nFindFirst: %d FNext %d "
> >> - "FClose %d",
> >> - atomic_read(&tcon->num_ffirst),
> >> - atomic_read(&tcon->num_fnext),
> >> - atomic_read(&tcon->num_fclose));
> >> + cifs_stats_print(m, tcon);
> >> }
> >> }
> >> }
> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> >> index 4c38b04..6dfc7ef 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -292,6 +292,7 @@ struct TCP_Server_Info {
> >> bool sec_kerberos; /* supports plain Kerberos */
> >> bool sec_mskerberos; /* supports legacy MS Kerberos */
> >> bool large_buf; /* is current buffer large? */
> >> + bool is_smb2; /* smb2 not cifs protocol negotiated */
> >> struct delayed_work echo; /* echo ping workqueue job */
> >> struct kvec *iov; /* reusable kvec array for receives */
> >> unsigned int nr_iov; /* number of kvecs in array */
> >> @@ -392,6 +393,9 @@ struct cifs_ses {
> >> negotiate one of the older LANMAN dialects */
> >> #define CIFS_SES_LANMAN 8
> >> #define CIFS_SES_SMB2 16
> >> +
> >> +#define NUMBER_OF_SMB2_COMMANDS 0x0013
> >> +
> >> /*
> >> * there is one of these for each connection to a resource on a particular
> >> * session
> >> @@ -409,27 +413,37 @@ struct cifs_tcon {
> >> enum statusEnum tidStatus;
> >> #ifdef CONFIG_CIFS_STATS
> >> atomic_t num_smbs_sent;
> >> - atomic_t num_writes;
> >> - atomic_t num_reads;
> >> - atomic_t num_flushes;
> >> - atomic_t num_oplock_brks;
> >> - atomic_t num_opens;
> >> - atomic_t num_closes;
> >> - atomic_t num_deletes;
> >> - atomic_t num_mkdirs;
> >> - atomic_t num_posixopens;
> >> - atomic_t num_posixmkdirs;
> >> - atomic_t num_rmdirs;
> >> - atomic_t num_renames;
> >> - atomic_t num_t2renames;
> >> - atomic_t num_ffirst;
> >> - atomic_t num_fnext;
> >> - atomic_t num_fclose;
> >> - atomic_t num_hardlinks;
> >> - atomic_t num_symlinks;
> >> - atomic_t num_locks;
> >> - atomic_t num_acl_get;
> >> - atomic_t num_acl_set;
> >> + union {
> >> + struct {
> >> + atomic_t num_writes;
> >> + atomic_t num_reads;
> >> + atomic_t num_flushes;
> >> + atomic_t num_oplock_brks;
> >> + atomic_t num_opens;
> >> + atomic_t num_closes;
> >> + atomic_t num_deletes;
> >> + atomic_t num_mkdirs;
> >> + atomic_t num_posixopens;
> >> + atomic_t num_posixmkdirs;
> >> + atomic_t num_rmdirs;
> >> + atomic_t num_renames;
> >> + atomic_t num_t2renames;
> >> + atomic_t num_ffirst;
> >> + atomic_t num_fnext;
> >> + atomic_t num_fclose;
> >> + atomic_t num_hardlinks;
> >> + atomic_t num_symlinks;
> >> + atomic_t num_locks;
> >> + atomic_t num_acl_get;
> >> + atomic_t num_acl_set;
> >> + } cifs_stats;
> >> +#ifdef CONFIG_CIFS_SMB2
> >> + struct {
> >> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
> >> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
> >> + } smb2_stats;
> >
> > Is it really necessary to do this with atomics? Those can have
> > significant performance impact (TLB flushes, and we don't seem to need the
> > guarantees that they provide for simple counters like this. Perhaps
> > these should be switched to per-cpu variables or just plain ints?
>
> presumably there is precedent for use of atomics rather than
> wrapping updates to these in a mutex - if they are just int
> would we have a case where the two overlapping updates could
> badly corrupt the value?
>
There's no need for any locking here. I think what you want is a per-cpu
counter for these.
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2)
[not found] ` <1319831704-3572-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-29 15:35 ` Jeff Layton
2011-10-29 20:00 ` Pavel Shilovsky
0 siblings, 1 reply; 75+ messages in thread
From: Jeff Layton @ 2011-10-29 15:35 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, 28 Oct 2011 23:54:16 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> wait_for_free_request is called to ensure that we don't have more than the
> configured maximum of requests in flight on the wire (for cifs), but for SMB2,
> the number of requests that can be in flight varies dynamically (the client
> may request that the server grant more "credits" in a request, and each
> request uses at least one credit). Instead of migrating over the original
> smb2_wait_for_free_request function, simply add a check in cifs's original
> wait_for_free_request for the is_smb2 case to make sure that we don't go
> beyond the number of allocated "credits" (ie those that remain from those
> the server has allocated for this tcp session). Otherwise the logic is unchanged
> (other than to make it extern so that the next function to be added, smb2_sendrcv2
> in smbtransport.c can call it - smb2_sendrcv2 will be migrated over in the next patch).
>
> Note that smb2 servers will typically allow many more requests in flight at one time
> than cifs servers (which usually default to only 50) and can adjust this as needed.
> This should provide significant performance benefit in some workloads (ie smb2
> in many cases will get more parallelism than cifs and some other protocols
> since some artificially constrain the maximum number of requests).
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifsglob.h | 1 +
> fs/cifs/cifsproto.h | 3 ++-
> fs/cifs/transport.c | 22 +++++++++++++++++++---
> 3 files changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 179b784..b440329 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -311,6 +311,7 @@ struct TCP_Server_Info {
> wait_queue_head_t read_q; /* used by readpages */
> atomic_t active_readpage_req; /* used by readpages */
> atomic_t resp_rdy; /* used by readpages and demultiplex */
> + atomic_t credits; /* send no more simultaneous requests than this */
> __le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
> struct task_struct *observe;
> char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index ef4f631..84d1e4c 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -1,7 +1,7 @@
> /*
> * fs/cifs/cifsproto.h
> *
> - * Copyright (c) International Business Machines Corp., 2002,2008
> + * Copyright (c) International Business Machines Corp., 2002,2011
> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> *
> * This library is free software; you can redistribute it and/or modify
> @@ -68,6 +68,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 int wait_for_free_request(struct TCP_Server_Info *sv, const int long_op);
> extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
> unsigned int nvec, mid_receive_t *receive,
> mid_callback_t *callback, void *cbdata,
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 0cc9584..25d04df 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -254,7 +254,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
> return smb_sendv(server, &iov, 1);
> }
>
> -static int wait_for_free_request(struct TCP_Server_Info *server,
> +int wait_for_free_request(struct TCP_Server_Info *server,
> const int long_op)
> {
> if (long_op == CIFS_ASYNC_OP) {
> @@ -265,7 +265,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>
> spin_lock(&GlobalMid_Lock);
> while (1) {
> - if (atomic_read(&server->inFlight) >= cifs_max_pending) {
> + if ((server->is_smb2 == false) &&
> + atomic_read(&server->inFlight) >= cifs_max_pending) {
> spin_unlock(&GlobalMid_Lock);
> cifs_num_waiters_inc(server);
> wait_event(server->request_q,
> @@ -273,6 +274,16 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
> < cifs_max_pending);
> cifs_num_waiters_dec(server);
> spin_lock(&GlobalMid_Lock);
> +#ifdef CONFIG_CIFS_SMB2
> + } else if (server->is_smb2 &&
> + (atomic_read(&server->credits) < 1)) {
> + spin_unlock(&GlobalMid_Lock);
> + cifs_num_waiters_inc(server);
> + wait_event(server->request_q,
> + atomic_read(&server->credits) > 0);
> + cifs_num_waiters_dec(server);
> + spin_lock(&GlobalMid_Lock);
> +#endif /* CONFIG_CIFS_SMB2 */
> } else {
> if (server->tcpStatus == CifsExiting) {
> spin_unlock(&GlobalMid_Lock);
> @@ -283,8 +294,13 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
> as they are allowed to block on server */
>
> /* update # of requests on the wire to server */
> - if (long_op != CIFS_BLOCKING_OP)
> + if (server->is_smb2 == false &&
> + long_op != CIFS_BLOCKING_OP)
> atomic_inc(&server->inFlight);
> +#ifdef CONFIG_CIFS_SMB2
> + else if (server->is_smb2)
> + atomic_dec(&server->credits);
> +#endif
> spin_unlock(&GlobalMid_Lock);
> break;
> }
This patch doesn't make much sense...
"credits" gets initialized to 0, then on the first request, you'll
decrement it which will make it go negative. I then don't see any place
where credits is ever incremented.
Maybe that happens in a different patch, but splitting your patches out
this way makes no sense. No one can reasonably review this patch for
sanity since the lifecycle of "credits" is incomplete.
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
[not found] ` <20111029004814.41340503-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2011-10-29 19:44 ` Pavel Shilovsky
[not found] ` <CAKywueQwBwR-HZtv6gQv32kt4+2qycS7vq5KDLiE3xw3_9=wPA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-29 19:44 UTC (permalink / raw)
To: Jeff Layton
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
2011/10/29 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
...
>> + union {
>> + struct {
>> + atomic_t num_writes;
>> + atomic_t num_reads;
>> + atomic_t num_flushes;
>> + atomic_t num_oplock_brks;
>> + atomic_t num_opens;
>> + atomic_t num_closes;
>> + atomic_t num_deletes;
>> + atomic_t num_mkdirs;
>> + atomic_t num_posixopens;
>> + atomic_t num_posixmkdirs;
>> + atomic_t num_rmdirs;
>> + atomic_t num_renames;
>> + atomic_t num_t2renames;
>> + atomic_t num_ffirst;
>> + atomic_t num_fnext;
>> + atomic_t num_fclose;
>> + atomic_t num_hardlinks;
>> + atomic_t num_symlinks;
>> + atomic_t num_locks;
>> + atomic_t num_acl_get;
>> + atomic_t num_acl_set;
>> + } cifs_stats;
>> +#ifdef CONFIG_CIFS_SMB2
>> + struct {
>> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
>> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
>> + } smb2_stats;
>
> Is it really necessary to do this with atomics? Those can have
> significant performance impact (TLB flushes, and we don't seem to need the
> guarantees that they provide for simple counters like this. Perhaps
> these should be switched to per-cpu variables or just plain ints?
I am not sure I understand your idea to make it as int. What's about
concurrency?
>
>> +#endif /* CONFIG CIFS_SMB2 */
>> + } stats;
>> #ifdef CONFIG_CIFS_STATS2
>> unsigned long long time_writes;
>> unsigned long long time_reads;
>> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> index ea7b813..4e11051 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -867,7 +867,7 @@ PsxDelete:
>> cFYI(1, "Posix delete returned %d", rc);
>> cifs_buf_release(pSMB);
>>
>> - cifs_stats_inc(&tcon->num_deletes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
>>
>> if (rc == -EAGAIN)
>> goto PsxDelete;
>> @@ -909,7 +909,7 @@ DelFileRetry:
>> pSMB->ByteCount = cpu_to_le16(name_len + 1);
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_deletes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
>> if (rc)
>> cFYI(1, "Error in RMFile = %d", rc);
>>
>> @@ -953,7 +953,7 @@ RmDirRetry:
>> pSMB->ByteCount = cpu_to_le16(name_len + 1);
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_rmdirs);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
>> if (rc)
>> cFYI(1, "Error in RMDir = %d", rc);
>>
>> @@ -996,7 +996,7 @@ MkDirRetry:
>> pSMB->ByteCount = cpu_to_le16(name_len + 1);
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_mkdirs);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
>> if (rc)
>> cFYI(1, "Error in Mkdir = %d", rc);
>>
>> @@ -1118,9 +1118,9 @@ psx_create_err:
>> cifs_buf_release(pSMB);
>>
>> if (posix_flags & SMB_O_DIRECTORY)
>> - cifs_stats_inc(&tcon->num_posixmkdirs);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
>> else
>> - cifs_stats_inc(&tcon->num_posixopens);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
>>
>> if (rc == -EAGAIN)
>> goto PsxCreat;
>> @@ -1241,7 +1241,7 @@ OldOpenRetry:
>> /* long_op set to 1 to allow for oplock break timeouts */
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *)pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_opens);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
>> if (rc) {
>> cFYI(1, "Error in Open = %d", rc);
>> } else {
>> @@ -1354,7 +1354,7 @@ openRetry:
>> /* long_op set to 1 to allow for oplock break timeouts */
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *)pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_opens);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
>> if (rc) {
>> cFYI(1, "Error in Open = %d", rc);
>> } else {
>> @@ -1728,7 +1728,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
>> rdata, false);
>>
>> if (rc == 0)
>> - cifs_stats_inc(&tcon->num_reads);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
>>
>> cifs_small_buf_release(smb);
>> return rc;
>> @@ -1796,7 +1796,7 @@ CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
>> iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
>> rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
>> &resp_buf_type, CIFS_LOG_ERROR);
>> - cifs_stats_inc(&tcon->num_reads);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
>> pSMBr = (READ_RSP *)iov[0].iov_base;
>> if (rc) {
>> cERROR(1, "Send error in read = %d", rc);
>> @@ -1948,7 +1948,7 @@ CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
>> - cifs_stats_inc(&tcon->num_writes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
>> if (rc) {
>> cFYI(1, "Send error in write = %d", rc);
>> } else {
>> @@ -2197,7 +2197,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
>> NULL, cifs_writev_callback, wdata, false);
>>
>> if (rc == 0)
>> - cifs_stats_inc(&tcon->num_writes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
>> else
>> kref_put(&wdata->refcount, cifs_writedata_release);
>>
>> @@ -2287,7 +2287,7 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
>>
>> rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
>> long_op);
>> - cifs_stats_inc(&tcon->num_writes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
>> if (rc) {
>> cFYI(1, "Send error Write2 = %d", rc);
>> } else if (resp_buf_type == 0) {
>> @@ -2353,7 +2353,7 @@ int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
>> iov[1].iov_base = (char *)buf;
>> iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
>>
>> - cifs_stats_inc(&tcon->num_locks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
>> rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
>> if (rc)
>> cFYI(1, "Send error in cifs_lockv = %d", rc);
>> @@ -2422,7 +2422,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
>> timeout);
>> /* SMB buffer freed by function above */
>> }
>> - cifs_stats_inc(&tcon->num_locks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
>> if (rc)
>> cFYI(1, "Send error in Lock = %d", rc);
>>
>> @@ -2587,7 +2587,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
>> pSMB->LastWriteTime = 0xFFFFFFFF;
>> pSMB->ByteCount = 0;
>> rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> - cifs_stats_inc(&tcon->num_closes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
>> if (rc) {
>> if (rc != -EINTR) {
>> /* EINTR is expected when user ctl-c to kill app */
>> @@ -2616,7 +2616,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
>> pSMB->FileID = (__u16) smb_file_id;
>> pSMB->ByteCount = 0;
>> rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> - cifs_stats_inc(&tcon->num_flushes);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
>> if (rc)
>> cERROR(1, "Send error in Flush = %d", rc);
>>
>> @@ -2679,7 +2679,7 @@ renameRetry:
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_renames);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
>> if (rc)
>> cFYI(1, "Send error in rename = %d", rc);
>>
>> @@ -2758,7 +2758,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
>> pSMB->ByteCount = cpu_to_le16(byte_count);
>> rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&pTcon->num_t2renames);
>> + cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
>> if (rc)
>> cFYI(1, "Send error in Rename (by file handle) = %d", rc);
>>
>> @@ -2915,7 +2915,7 @@ createSymLinkRetry:
>> pSMB->ByteCount = cpu_to_le16(byte_count);
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_symlinks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
>> if (rc)
>> cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
>>
>> @@ -3001,7 +3001,7 @@ createHardLinkRetry:
>> pSMB->ByteCount = cpu_to_le16(byte_count);
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_hardlinks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
>> if (rc)
>> cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
>>
>> @@ -3073,7 +3073,7 @@ winCreateHardLinkRetry:
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_hardlinks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
>> if (rc)
>> cFYI(1, "Send error in hard link (NT rename) = %d", rc);
>>
>> @@ -3490,7 +3490,7 @@ queryAclRetry:
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_acl_get);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
>> if (rc) {
>> cFYI(1, "Send error in Query POSIX ACL = %d", rc);
>> } else {
>> @@ -3801,7 +3801,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
>>
>> rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
>> 0);
>> - cifs_stats_inc(&tcon->num_acl_get);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
>> if (rc) {
>> cFYI(1, "Send error in QuerySecDesc = %d", rc);
>> } else { /* decode response */
>> @@ -4405,7 +4405,7 @@ findFirstRetry:
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_ffirst);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
>>
>> if (rc) {/* BB add logic to retry regular search if Unix search
>> rejected unexpectedly by server */
>> @@ -4532,7 +4532,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
>>
>> rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> - cifs_stats_inc(&tcon->num_fnext);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
>> if (rc) {
>> if (rc == -EBADF) {
>> psrch_inf->endOfSearch = true;
>> @@ -4623,7 +4623,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
>> if (rc)
>> cERROR(1, "Send error in FindClose = %d", rc);
>>
>> - cifs_stats_inc(&tcon->num_fclose);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
>>
>> /* Since session is dead, search handle closed on server already */
>> if (rc == -EAGAIN)
>> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
>> index 703ef5c..1934575 100644
>> --- a/fs/cifs/misc.c
>> +++ b/fs/cifs/misc.c
>> @@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
>> if (tcon->tid != buf->Tid)
>> continue;
>>
>> - cifs_stats_inc(&tcon->num_oplock_brks);
>> + cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
>> spin_lock(&cifs_file_list_lock);
>> list_for_each(tmp2, &tcon->openFileList) {
>> netfile = list_entry(tmp2, struct cifsFileInfo,
>
>
> --
> 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] 75+ messages in thread
* Re: [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session
[not found] ` <20111029004046.2bf8e111-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2011-10-29 19:55 ` Pavel Shilovsky
0 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-29 19:55 UTC (permalink / raw)
To: Jeff Layton
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
2011/10/29 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> On Fri, 28 Oct 2011 23:54:14 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>>
>> Also set ses->is_smb2 when smb2 session initialized.
>>
>
> The commit message doesn't seem to be accurate. ses->is_smb2 is not
> being set here (and doesn't seem to exist).
Good catch - will fix this. Thanks!
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2)
2011-10-29 15:35 ` Jeff Layton
@ 2011-10-29 20:00 ` Pavel Shilovsky
[not found] ` <CAKywueSGDSw33L4_a7W6D7gM_PH9uy3xTQ6=8zgAimGhz5=UfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-10-29 20:00 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs, linux-fsdevel, Steve French
2011/10/29 Jeff Layton <jlayton@samba.org>:
> On Fri, 28 Oct 2011 23:54:16 +0400
> Pavel Shilovsky <piastry@etersoft.ru> wrote:
>
>> From: Steve French <sfrench@us.ibm.com>
>>
>> wait_for_free_request is called to ensure that we don't have more than the
>> configured maximum of requests in flight on the wire (for cifs), but for SMB2,
>> the number of requests that can be in flight varies dynamically (the client
>> may request that the server grant more "credits" in a request, and each
>> request uses at least one credit). Instead of migrating over the original
>> smb2_wait_for_free_request function, simply add a check in cifs's original
>> wait_for_free_request for the is_smb2 case to make sure that we don't go
>> beyond the number of allocated "credits" (ie those that remain from those
>> the server has allocated for this tcp session). Otherwise the logic is unchanged
>> (other than to make it extern so that the next function to be added, smb2_sendrcv2
>> in smbtransport.c can call it - smb2_sendrcv2 will be migrated over in the next patch).
>>
>> Note that smb2 servers will typically allow many more requests in flight at one time
>> than cifs servers (which usually default to only 50) and can adjust this as needed.
>> This should provide significant performance benefit in some workloads (ie smb2
>> in many cases will get more parallelism than cifs and some other protocols
>> since some artificially constrain the maximum number of requests).
>>
>> Signed-off-by: Steve French <sfrench@us.ibm.com>
>> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
>> ---
>> fs/cifs/cifsglob.h | 1 +
>> fs/cifs/cifsproto.h | 3 ++-
>> fs/cifs/transport.c | 22 +++++++++++++++++++---
>> 3 files changed, 22 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 179b784..b440329 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -311,6 +311,7 @@ struct TCP_Server_Info {
>> wait_queue_head_t read_q; /* used by readpages */
>> atomic_t active_readpage_req; /* used by readpages */
>> atomic_t resp_rdy; /* used by readpages and demultiplex */
>> + atomic_t credits; /* send no more simultaneous requests than this */
>> __le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
>> struct task_struct *observe;
>> char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index ef4f631..84d1e4c 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -1,7 +1,7 @@
>> /*
>> * fs/cifs/cifsproto.h
>> *
>> - * Copyright (c) International Business Machines Corp., 2002,2008
>> + * Copyright (c) International Business Machines Corp., 2002,2011
>> * Author(s): Steve French (sfrench@us.ibm.com)
>> *
>> * This library is free software; you can redistribute it and/or modify
>> @@ -68,6 +68,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 int wait_for_free_request(struct TCP_Server_Info *sv, const int long_op);
>> extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>> unsigned int nvec, mid_receive_t *receive,
>> mid_callback_t *callback, void *cbdata,
>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>> index 0cc9584..25d04df 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -254,7 +254,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>> return smb_sendv(server, &iov, 1);
>> }
>>
>> -static int wait_for_free_request(struct TCP_Server_Info *server,
>> +int wait_for_free_request(struct TCP_Server_Info *server,
>> const int long_op)
>> {
>> if (long_op == CIFS_ASYNC_OP) {
>> @@ -265,7 +265,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>>
>> spin_lock(&GlobalMid_Lock);
>> while (1) {
>> - if (atomic_read(&server->inFlight) >= cifs_max_pending) {
>> + if ((server->is_smb2 == false) &&
>> + atomic_read(&server->inFlight) >= cifs_max_pending) {
>> spin_unlock(&GlobalMid_Lock);
>> cifs_num_waiters_inc(server);
>> wait_event(server->request_q,
>> @@ -273,6 +274,16 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>> < cifs_max_pending);
>> cifs_num_waiters_dec(server);
>> spin_lock(&GlobalMid_Lock);
>> +#ifdef CONFIG_CIFS_SMB2
>> + } else if (server->is_smb2 &&
>> + (atomic_read(&server->credits) < 1)) {
>> + spin_unlock(&GlobalMid_Lock);
>> + cifs_num_waiters_inc(server);
>> + wait_event(server->request_q,
>> + atomic_read(&server->credits) > 0);
>> + cifs_num_waiters_dec(server);
>> + spin_lock(&GlobalMid_Lock);
>> +#endif /* CONFIG_CIFS_SMB2 */
>> } else {
>> if (server->tcpStatus == CifsExiting) {
>> spin_unlock(&GlobalMid_Lock);
>> @@ -283,8 +294,13 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>> as they are allowed to block on server */
>>
>> /* update # of requests on the wire to server */
>> - if (long_op != CIFS_BLOCKING_OP)
>> + if (server->is_smb2 == false &&
>> + long_op != CIFS_BLOCKING_OP)
>> atomic_inc(&server->inFlight);
>> +#ifdef CONFIG_CIFS_SMB2
>> + else if (server->is_smb2)
>> + atomic_dec(&server->credits);
>> +#endif
>> spin_unlock(&GlobalMid_Lock);
>> break;
>> }
>
> This patch doesn't make much sense...
>
> "credits" gets initialized to 0, then on the first request, you'll
> decrement it which will make it go negative. I then don't see any place
> where credits is ever incremented.
>
> Maybe that happens in a different patch, but splitting your patches out
> this way makes no sense. No one can reasonably review this patch for
> sanity since the lifecycle of "credits" is incomplete.
In this case we should move this patch after we add smb2_sendrcv
function (where credits are increased). Make sense?
--
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
[not found] ` <CAKywueQwBwR-HZtv6gQv32kt4+2qycS7vq5KDLiE3xw3_9=wPA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-10-30 2:12 ` Jeff Layton
[not found] ` <20111029221251.5fba1444-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
0 siblings, 1 reply; 75+ messages in thread
From: Jeff Layton @ 2011-10-30 2:12 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Sat, 29 Oct 2011 23:44:53 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 2011/10/29 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> ...
> >> + union {
> >> + struct {
> >> + atomic_t num_writes;
> >> + atomic_t num_reads;
> >> + atomic_t num_flushes;
> >> + atomic_t num_oplock_brks;
> >> + atomic_t num_opens;
> >> + atomic_t num_closes;
> >> + atomic_t num_deletes;
> >> + atomic_t num_mkdirs;
> >> + atomic_t num_posixopens;
> >> + atomic_t num_posixmkdirs;
> >> + atomic_t num_rmdirs;
> >> + atomic_t num_renames;
> >> + atomic_t num_t2renames;
> >> + atomic_t num_ffirst;
> >> + atomic_t num_fnext;
> >> + atomic_t num_fclose;
> >> + atomic_t num_hardlinks;
> >> + atomic_t num_symlinks;
> >> + atomic_t num_locks;
> >> + atomic_t num_acl_get;
> >> + atomic_t num_acl_set;
> >> + } cifs_stats;
> >> +#ifdef CONFIG_CIFS_SMB2
> >> + struct {
> >> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
> >> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
> >> + } smb2_stats;
> >
> > Is it really necessary to do this with atomics? Those can have
> > significant performance impact (TLB flushes, and we don't seem to need the
> > guarantees that they provide for simple counters like this. Perhaps
> > these should be switched to per-cpu variables or just plain ints?
>
> I am not sure I understand your idea to make it as int. What's about
> concurrency?
>
Sorry, I was reviewing these while on little sleep. We do need to worry
about concurrency here so ints are probably not appropriate (unless
these are already being incremented under a lock of some sort). Percpu
variables though would be ideal for this.
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2)
[not found] ` <CAKywueSGDSw33L4_a7W6D7gM_PH9uy3xTQ6=8zgAimGhz5=UfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-10-30 2:41 ` Jeff Layton
0 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2011-10-30 2:41 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Sun, 30 Oct 2011 00:00:15 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 2011/10/29 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> > On Fri, 28 Oct 2011 23:54:16 +0400
> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >
> >> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >>
> >> wait_for_free_request is called to ensure that we don't have more than the
> >> configured maximum of requests in flight on the wire (for cifs), but for SMB2,
> >> the number of requests that can be in flight varies dynamically (the client
> >> may request that the server grant more "credits" in a request, and each
> >> request uses at least one credit). Instead of migrating over the original
> >> smb2_wait_for_free_request function, simply add a check in cifs's original
> >> wait_for_free_request for the is_smb2 case to make sure that we don't go
> >> beyond the number of allocated "credits" (ie those that remain from those
> >> the server has allocated for this tcp session). Otherwise the logic is unchanged
> >> (other than to make it extern so that the next function to be added, smb2_sendrcv2
> >> in smbtransport.c can call it - smb2_sendrcv2 will be migrated over in the next patch).
> >>
> >> Note that smb2 servers will typically allow many more requests in flight at one time
> >> than cifs servers (which usually default to only 50) and can adjust this as needed.
> >> This should provide significant performance benefit in some workloads (ie smb2
> >> in many cases will get more parallelism than cifs and some other protocols
> >> since some artificially constrain the maximum number of requests).
> >>
> >> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >> ---
> >> fs/cifs/cifsglob.h | 1 +
> >> fs/cifs/cifsproto.h | 3 ++-
> >> fs/cifs/transport.c | 22 +++++++++++++++++++---
> >> 3 files changed, 22 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> >> index 179b784..b440329 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -311,6 +311,7 @@ struct TCP_Server_Info {
> >> wait_queue_head_t read_q; /* used by readpages */
> >> atomic_t active_readpage_req; /* used by readpages */
> >> atomic_t resp_rdy; /* used by readpages and demultiplex */
> >> + atomic_t credits; /* send no more simultaneous requests than this */
> >> __le16 smb2_dialect_revision; /* SMB2.0 implemented, 2.1 recognized */
> >> struct task_struct *observe;
> >> char smb2_crypt_key[CIFS_CRYPTO_KEY_SIZE]; /* BB can we use cifs key */
> >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> >> index ef4f631..84d1e4c 100644
> >> --- a/fs/cifs/cifsproto.h
> >> +++ b/fs/cifs/cifsproto.h
> >> @@ -1,7 +1,7 @@
> >> /*
> >> * fs/cifs/cifsproto.h
> >> *
> >> - * Copyright (c) International Business Machines Corp., 2002,2008
> >> + * Copyright (c) International Business Machines Corp., 2002,2011
> >> * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
> >> *
> >> * This library is free software; you can redistribute it and/or modify
> >> @@ -68,6 +68,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 int wait_for_free_request(struct TCP_Server_Info *sv, const int long_op);
> >> extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
> >> unsigned int nvec, mid_receive_t *receive,
> >> mid_callback_t *callback, void *cbdata,
> >> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> >> index 0cc9584..25d04df 100644
> >> --- a/fs/cifs/transport.c
> >> +++ b/fs/cifs/transport.c
> >> @@ -254,7 +254,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
> >> return smb_sendv(server, &iov, 1);
> >> }
> >>
> >> -static int wait_for_free_request(struct TCP_Server_Info *server,
> >> +int wait_for_free_request(struct TCP_Server_Info *server,
> >> const int long_op)
> >> {
> >> if (long_op == CIFS_ASYNC_OP) {
> >> @@ -265,7 +265,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
> >>
> >> spin_lock(&GlobalMid_Lock);
> >> while (1) {
> >> - if (atomic_read(&server->inFlight) >= cifs_max_pending) {
> >> + if ((server->is_smb2 == false) &&
> >> + atomic_read(&server->inFlight) >= cifs_max_pending) {
> >> spin_unlock(&GlobalMid_Lock);
> >> cifs_num_waiters_inc(server);
> >> wait_event(server->request_q,
> >> @@ -273,6 +274,16 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
> >> < cifs_max_pending);
> >> cifs_num_waiters_dec(server);
> >> spin_lock(&GlobalMid_Lock);
> >> +#ifdef CONFIG_CIFS_SMB2
> >> + } else if (server->is_smb2 &&
> >> + (atomic_read(&server->credits) < 1)) {
> >> + spin_unlock(&GlobalMid_Lock);
> >> + cifs_num_waiters_inc(server);
> >> + wait_event(server->request_q,
> >> + atomic_read(&server->credits) > 0);
> >> + cifs_num_waiters_dec(server);
> >> + spin_lock(&GlobalMid_Lock);
> >> +#endif /* CONFIG_CIFS_SMB2 */
> >> } else {
> >> if (server->tcpStatus == CifsExiting) {
> >> spin_unlock(&GlobalMid_Lock);
> >> @@ -283,8 +294,13 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
> >> as they are allowed to block on server */
> >>
> >> /* update # of requests on the wire to server */
> >> - if (long_op != CIFS_BLOCKING_OP)
> >> + if (server->is_smb2 == false &&
> >> + long_op != CIFS_BLOCKING_OP)
> >> atomic_inc(&server->inFlight);
> >> +#ifdef CONFIG_CIFS_SMB2
> >> + else if (server->is_smb2)
> >> + atomic_dec(&server->credits);
> >> +#endif
> >> spin_unlock(&GlobalMid_Lock);
> >> break;
> >> }
> >
> > This patch doesn't make much sense...
> >
> > "credits" gets initialized to 0, then on the first request, you'll
> > decrement it which will make it go negative. I then don't see any place
> > where credits is ever incremented.
> >
> > Maybe that happens in a different patch, but splitting your patches out
> > this way makes no sense. No one can reasonably review this patch for
> > sanity since the lifecycle of "credits" is incomplete.
>
> In this case we should move this patch after we add smb2_sendrcv
> function (where credits are increased). Make sense?
>
I haven't gotten that far in the series yet, so I'm not sure if that
makes sense or not. That's the problem: we as reviewers can't review
this set as a whole. Most of us don't have brains that big. We have to
review these patches a set of individual changes that are working
toward a goal.
I think what you need to do is to figure out a way to break the
patchset up more logically. One would think that doing that would be a
set of steps that you could follow, but it's really more of an art. You
have to look at this from the viewpoint of potential reviewers.
A large patchset like this needs to have a clear "flow" that evolves
the code incrementally. Cleanups or other changes that make sense on
their own should usually be broken out and done first, and often in a
separate set. Further patches should make a set of logically complete
changes to the code.
A case in point: when I did the patchset to clean up the demultiplex
codepath, I added code to kmalloc a buffer on each pass through
readv_from_socket. In the next patch, I ripped that kmalloc back out
and added code to keep a reusable buffer for that purpose.
I could have done that in a different way that didn't "churn" the code
so much, but it made more sense to do it that way for a reviewer walking
the patches in order. Adding the new buffer management was logically
separate from the earlier change, so I broke the patches up along the
same lines.
Doing this also pays off later. It also allows for someone bisecting
the code to have a tree that reasonably works if they stop at that
point, and makes it easier to find bugs since the change is more
logical.
Sometimes it is necessary to have a patch that doesn't make a lot of
sense on its own in order to prepare for later patches. If you do that
though, you really need to have a commit message that explains what
you're doing and why.
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked
[not found] ` <20111029221251.5fba1444-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
@ 2011-10-30 2:52 ` Steve French
0 siblings, 0 replies; 75+ messages in thread
From: Steve French @ 2011-10-30 2:52 UTC (permalink / raw)
To: Jeff Layton
Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Sat, Oct 29, 2011 at 9:12 PM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Sat, 29 Oct 2011 23:44:53 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 2011/10/29 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
>> ...
>> >> + union {
>> >> + struct {
>> >> + atomic_t num_writes;
>> >> + atomic_t num_reads;
>> >> + atomic_t num_flushes;
>> >> + atomic_t num_oplock_brks;
>> >> + atomic_t num_opens;
>> >> + atomic_t num_closes;
>> >> + atomic_t num_deletes;
>> >> + atomic_t num_mkdirs;
>> >> + atomic_t num_posixopens;
>> >> + atomic_t num_posixmkdirs;
>> >> + atomic_t num_rmdirs;
>> >> + atomic_t num_renames;
>> >> + atomic_t num_t2renames;
>> >> + atomic_t num_ffirst;
>> >> + atomic_t num_fnext;
>> >> + atomic_t num_fclose;
>> >> + atomic_t num_hardlinks;
>> >> + atomic_t num_symlinks;
>> >> + atomic_t num_locks;
>> >> + atomic_t num_acl_get;
>> >> + atomic_t num_acl_set;
>> >> + } cifs_stats;
>> >> +#ifdef CONFIG_CIFS_SMB2
>> >> + struct {
>> >> + atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS];
>> >> + atomic_t smb2_com_fail[NUMBER_OF_SMB2_COMMANDS];
>> >> + } smb2_stats;
>> >
>> > Is it really necessary to do this with atomics? Those can have
>> > significant performance impact (TLB flushes, and we don't seem to need the
>> > guarantees that they provide for simple counters like this. Perhaps
>> > these should be switched to per-cpu variables or just plain ints?
>>
>> I am not sure I understand your idea to make it as int. What's about
>> concurrency?
>>
>
> Sorry, I was reviewing these while on little sleep. We do need to worry
> about concurrency here so ints are probably not appropriate (unless
> these are already being incremented under a lock of some sort). Percpu
> variables though would be ideal for this.
Using per-cpu variables sounds reasonable, but that seems like something
that is lower priority (than much of your other patch feedback) for Pavel
to change in the short term since the current approach works
(albeit slightly slower when STATS2 is enabled).
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-11-01 10:12 ` Jeff Layton
2011-11-01 13:52 ` Shirish Pargaonkar
` (2 subsequent siblings)
3 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2011-11-01 10:12 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, 28 Oct 2011 23:54:17 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/cifs/cifs_unicode.h | 7 +++++
> 2 files changed, 68 insertions(+), 0 deletions(-)
>
> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> index 1b2e180..7f09423 100644
> --- a/fs/cifs/cifs_unicode.c
> +++ b/fs/cifs/cifs_unicode.c
> @@ -330,3 +330,64 @@ ctoUCS_out:
> return i;
> }
>
> +#ifdef CONFIG_CIFS_SMB2
> +/*
> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> + * @from - pointer to input string
> + * @maxbytes - don't go past this many bytes of input string
> + * @codepage - source codepage
> + *
> + * Walk a string and return the number of bytes that the string will
> + * be after being converted to the given charset, not including any null
> + * termination required. Don't walk past maxbytes in the source buffer.
> + */
> +
> +int
> +smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage)
> +{
> + int charlen;
> + int i;
> + wchar_t wchar_to;
> +
> + if (from == NULL)
> + return 0;
> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> + charlen = codepage->char2uni(from, len, &wchar_to);
> + /* Failed conversion defaults to a question mark */
> + if (charlen < 1)
> + charlen = 1;
> + }
> + return 2 * i; /* UCS characters are two bytes */
> +}
> +
> +/*
> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> + * @src - source string
> + * @maxlen - don't walk past this many bytes in the source string
> + * @ucslen - the length of the allocated string in bytes (including null)
> + * @codepage - source codepage
> + *
> + * Take a string convert it from the local codepage to UCS2 and
> + * put it in a new buffer. Returns a pointer to the new string or NULL on
> + * error.
> + */
> +__le16 *
> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> + const struct nls_table *codepage)
> +{
> + int len;
> + __le16 *dst;
> +
> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> + len += 2; /* NULL */
> + dst = kmalloc(len, GFP_KERNEL);
> + if (!dst) {
> + *ucs_len = 0;
> + return NULL;
> + }
> + cifs_strtoUCS(dst, src, maxlen, codepage);
> + *ucs_len = len;
> + return dst;
> +}
> +#endif /* CONFIG_CIFS_SMB2 */
> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> index 6d02fd5..e00f677 100644
> --- a/fs/cifs/cifs_unicode.h
> +++ b/fs/cifs/cifs_unicode.h
> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>
> #endif
>
> +#ifdef CONFIG_CIFS_SMB2
> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage);
> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> + int *ucs_len, const struct nls_table *cp);
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> #endif /* _CIFS_UNICODE_H */
Since you're adding these functions with no callers, it would be
helpful to clarify (in the commit message) how these will be used.
--
Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-11-01 10:12 ` Jeff Layton
@ 2011-11-01 13:52 ` Shirish Pargaonkar
2011-12-29 15:01 ` Pavel Shilovsky
2012-01-12 17:22 ` Shirish Pargaonkar
2012-01-12 20:41 ` Shirish Pargaonkar
3 siblings, 1 reply; 75+ messages in thread
From: Shirish Pargaonkar @ 2011-11-01 13:52 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/cifs/cifs_unicode.h | 7 +++++
> 2 files changed, 68 insertions(+), 0 deletions(-)
>
> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> index 1b2e180..7f09423 100644
> --- a/fs/cifs/cifs_unicode.c
> +++ b/fs/cifs/cifs_unicode.c
> @@ -330,3 +330,64 @@ ctoUCS_out:
> return i;
> }
>
> +#ifdef CONFIG_CIFS_SMB2
> +/*
> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> + * @from - pointer to input string
> + * @maxbytes - don't go past this many bytes of input string
> + * @codepage - source codepage
> + *
> + * Walk a string and return the number of bytes that the string will
> + * be after being converted to the given charset, not including any null
> + * termination required. Don't walk past maxbytes in the source buffer.
> + */
> +
> +int
> +smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage)
> +{
> + int charlen;
> + int i;
> + wchar_t wchar_to;
> +
> + if (from == NULL)
> + return 0;
> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> + charlen = codepage->char2uni(from, len, &wchar_to);
> + /* Failed conversion defaults to a question mark */
> + if (charlen < 1)
> + charlen = 1;
> + }
> + return 2 * i; /* UCS characters are two bytes */
> +}
> +
> +/*
> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> + * @src - source string
> + * @maxlen - don't walk past this many bytes in the source string
> + * @ucslen - the length of the allocated string in bytes (including null)
> + * @codepage - source codepage
> + *
> + * Take a string convert it from the local codepage to UCS2 and
> + * put it in a new buffer. Returns a pointer to the new string or NULL on
> + * error.
> + */
> +__le16 *
> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> + const struct nls_table *codepage)
> +{
> + int len;
> + __le16 *dst;
> +
> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> + len += 2; /* NULL */
> + dst = kmalloc(len, GFP_KERNEL);
> + if (!dst) {
> + *ucs_len = 0;
> + return NULL;
> + }
> + cifs_strtoUCS(dst, src, maxlen, codepage);
> + *ucs_len = len;
> + return dst;
> +}
> +#endif /* CONFIG_CIFS_SMB2 */
> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> index 6d02fd5..e00f677 100644
> --- a/fs/cifs/cifs_unicode.h
> +++ b/fs/cifs/cifs_unicode.h
> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>
> #endif
>
> +#ifdef CONFIG_CIFS_SMB2
> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage);
> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> + int *ucs_len, const struct nls_table *cp);
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> #endif /* _CIFS_UNICODE_H */
> --
> 1.7.1
>
> --
> 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
>
Should these functions be renamed to *utf16* instead of *ucs*
to reflect the unicode encoding used in cifs/smb2 protocol?
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
2011-11-01 13:52 ` Shirish Pargaonkar
@ 2011-12-29 15:01 ` Pavel Shilovsky
2011-12-30 12:42 ` Jeff Layton
0 siblings, 1 reply; 75+ messages in thread
From: Pavel Shilovsky @ 2011-12-29 15:01 UTC (permalink / raw)
To: Shirish Pargaonkar, Steve French, Jeff Layton; +Cc: linux-cifs, linux-fsdevel
2011/11/1 Shirish Pargaonkar <shirishpargaonkar@gmail.com>:
> On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>> From: Steve French <sfrench@us.ibm.com>
>>
>> Signed-off-by: Steve French <sfrench@us.ibm.com>
>> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
>> ---
>> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
>> fs/cifs/cifs_unicode.h | 7 +++++
>> 2 files changed, 68 insertions(+), 0 deletions(-)
>>
>> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
>> index 1b2e180..7f09423 100644
>> --- a/fs/cifs/cifs_unicode.c
>> +++ b/fs/cifs/cifs_unicode.c
>> @@ -330,3 +330,64 @@ ctoUCS_out:
>> return i;
>> }
>>
>> +#ifdef CONFIG_CIFS_SMB2
>> +/*
>> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
>> + * @from - pointer to input string
>> + * @maxbytes - don't go past this many bytes of input string
>> + * @codepage - source codepage
>> + *
>> + * Walk a string and return the number of bytes that the string will
>> + * be after being converted to the given charset, not including any null
>> + * termination required. Don't walk past maxbytes in the source buffer.
>> + */
>> +
>> +int
>> +smb2_local_to_ucs2_bytes(const char *from, int len,
>> + const struct nls_table *codepage)
>> +{
>> + int charlen;
>> + int i;
>> + wchar_t wchar_to;
>> +
>> + if (from == NULL)
>> + return 0;
>> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
>> + charlen = codepage->char2uni(from, len, &wchar_to);
>> + /* Failed conversion defaults to a question mark */
>> + if (charlen < 1)
>> + charlen = 1;
>> + }
>> + return 2 * i; /* UCS characters are two bytes */
>> +}
>> +
>> +/*
>> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
>> + * @src - source string
>> + * @maxlen - don't walk past this many bytes in the source string
>> + * @ucslen - the length of the allocated string in bytes (including null)
>> + * @codepage - source codepage
>> + *
>> + * Take a string convert it from the local codepage to UCS2 and
>> + * put it in a new buffer. Returns a pointer to the new string or NULL on
>> + * error.
>> + */
>> +__le16 *
>> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
>> + const struct nls_table *codepage)
>> +{
>> + int len;
>> + __le16 *dst;
>> +
>> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
>> + len += 2; /* NULL */
>> + dst = kmalloc(len, GFP_KERNEL);
>> + if (!dst) {
>> + *ucs_len = 0;
>> + return NULL;
>> + }
>> + cifs_strtoUCS(dst, src, maxlen, codepage);
>> + *ucs_len = len;
>> + return dst;
>> +}
>> +#endif /* CONFIG_CIFS_SMB2 */
>> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
>> index 6d02fd5..e00f677 100644
>> --- a/fs/cifs/cifs_unicode.h
>> +++ b/fs/cifs/cifs_unicode.h
>> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>>
>> #endif
>>
>> +#ifdef CONFIG_CIFS_SMB2
>> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
>> + const struct nls_table *codepage);
>> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
>> + int *ucs_len, const struct nls_table *cp);
>> +#endif /* CONFIG_CIFS_SMB2 */
>> +
>> #endif /* _CIFS_UNICODE_H */
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> Should these functions be renamed to *utf16* instead of *ucs*
> to reflect the unicode encoding used in cifs/smb2 protocol?
Seems no problem to rename it.
Jeff, Steve, thoughts? If no objections - I will rename *ucs* to *utf16*.
--
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
2011-12-29 15:01 ` Pavel Shilovsky
@ 2011-12-30 12:42 ` Jeff Layton
2012-01-12 10:47 ` Pavel Shilovsky
0 siblings, 1 reply; 75+ messages in thread
From: Jeff Layton @ 2011-12-30 12:42 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: Shirish Pargaonkar, Steve French, linux-cifs, linux-fsdevel
On Thu, 29 Dec 2011 19:01:24 +0400
Pavel Shilovsky <piastry@etersoft.ru> wrote:
> 2011/11/1 Shirish Pargaonkar <shirishpargaonkar@gmail.com>:
> > On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
> >> From: Steve French <sfrench@us.ibm.com>
> >>
> >> Signed-off-by: Steve French <sfrench@us.ibm.com>
> >> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
> >> ---
> >> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> fs/cifs/cifs_unicode.h | 7 +++++
> >> 2 files changed, 68 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> >> index 1b2e180..7f09423 100644
> >> --- a/fs/cifs/cifs_unicode.c
> >> +++ b/fs/cifs/cifs_unicode.c
> >> @@ -330,3 +330,64 @@ ctoUCS_out:
> >> return i;
> >> }
> >>
> >> +#ifdef CONFIG_CIFS_SMB2
> >> +/*
> >> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> >> + * @from - pointer to input string
> >> + * @maxbytes - don't go past this many bytes of input string
> >> + * @codepage - source codepage
> >> + *
> >> + * Walk a string and return the number of bytes that the string will
> >> + * be after being converted to the given charset, not including any null
> >> + * termination required. Don't walk past maxbytes in the source buffer.
> >> + */
> >> +
> >> +int
> >> +smb2_local_to_ucs2_bytes(const char *from, int len,
> >> + const struct nls_table *codepage)
> >> +{
> >> + int charlen;
> >> + int i;
> >> + wchar_t wchar_to;
> >> +
> >> + if (from == NULL)
> >> + return 0;
^^^^^^^^
Are there really cases where you'll pass in a NULL pointer here?
> >> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> >> + charlen = codepage->char2uni(from, len, &wchar_to);
^^^^
This may result in an unaligned
access. You should use
put_unaligned to place this
in the string.
> >> + /* Failed conversion defaults to a question mark */
> >> + if (charlen < 1)
> >> + charlen = 1;
> >> + }
> >> + return 2 * i; /* UCS characters are two bytes */
> >> +}
> >> +
> >> +/*
> >> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> >> + * @src - source string
> >> + * @maxlen - don't walk past this many bytes in the source string
> >> + * @ucslen - the length of the allocated string in bytes (including null)
> >> + * @codepage - source codepage
> >> + *
> >> + * Take a string convert it from the local codepage to UCS2 and
> >> + * put it in a new buffer. Returns a pointer to the new string or NULL on
> >> + * error.
> >> + */
> >> +__le16 *
> >> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> >> + const struct nls_table *codepage)
> >> +{
> >> + int len;
> >> + __le16 *dst;
> >> +
> >> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> >> + len += 2; /* NULL */
> >> + dst = kmalloc(len, GFP_KERNEL);
> >> + if (!dst) {
> >> + *ucs_len = 0;
> >> + return NULL;
> >> + }
> >> + cifs_strtoUCS(dst, src, maxlen, codepage);
> >> + *ucs_len = len;
> >> + return dst;
> >> +}
> >> +#endif /* CONFIG_CIFS_SMB2 */
> >> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> >> index 6d02fd5..e00f677 100644
> >> --- a/fs/cifs/cifs_unicode.h
> >> +++ b/fs/cifs/cifs_unicode.h
> >> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
> >>
> >> #endif
> >>
> >> +#ifdef CONFIG_CIFS_SMB2
> >> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> >> + const struct nls_table *codepage);
> >> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> >> + int *ucs_len, const struct nls_table *cp);
> >> +#endif /* CONFIG_CIFS_SMB2 */
> >> +
> >> #endif /* _CIFS_UNICODE_H */
> >> --
> >> 1.7.1
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> >>
> >
> > Should these functions be renamed to *utf16* instead of *ucs*
> > to reflect the unicode encoding used in cifs/smb2 protocol?
>
> Seems no problem to rename it.
>
> Jeff, Steve, thoughts? If no objections - I will rename *ucs* to *utf16*.
>
Yeah, now that I look over the NLS code, it does seem to be converting
to UTF16 and not to UCS2. You should probably rename the existing *ucs*
functions in cifs_unicode.c as well.
Also, we should probably settle on a prefix for these that makes sense.
These are only currently used by smb2 code, but they aren't truly
smb2-specific. I'd name them cifs_* myself, but maybe something more
neutral makes sense?
--
Jeff Layton <jlayton@redhat.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
2011-12-30 12:42 ` Jeff Layton
@ 2012-01-12 10:47 ` Pavel Shilovsky
0 siblings, 0 replies; 75+ messages in thread
From: Pavel Shilovsky @ 2012-01-12 10:47 UTC (permalink / raw)
To: Jeff Layton; +Cc: Shirish Pargaonkar, Steve French, linux-cifs, linux-fsdevel
2011/12/30 Jeff Layton <jlayton@redhat.com>:
> On Thu, 29 Dec 2011 19:01:24 +0400
> Pavel Shilovsky <piastry@etersoft.ru> wrote:
>
>> 2011/11/1 Shirish Pargaonkar <shirishpargaonkar@gmail.com>:
>> > On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>> >> From: Steve French <sfrench@us.ibm.com>
>> >>
>> >> Signed-off-by: Steve French <sfrench@us.ibm.com>
>> >> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
>> >> ---
>> >> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
>> >> fs/cifs/cifs_unicode.h | 7 +++++
>> >> 2 files changed, 68 insertions(+), 0 deletions(-)
>> >>
>> >> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
>> >> index 1b2e180..7f09423 100644
>> >> --- a/fs/cifs/cifs_unicode.c
>> >> +++ b/fs/cifs/cifs_unicode.c
>> >> @@ -330,3 +330,64 @@ ctoUCS_out:
>> >> return i;
>> >> }
>> >>
>> >> +#ifdef CONFIG_CIFS_SMB2
>> >> +/*
>> >> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
>> >> + * @from - pointer to input string
>> >> + * @maxbytes - don't go past this many bytes of input string
>> >> + * @codepage - source codepage
>> >> + *
>> >> + * Walk a string and return the number of bytes that the string will
>> >> + * be after being converted to the given charset, not including any null
>> >> + * termination required. Don't walk past maxbytes in the source buffer.
>> >> + */
>> >> +
>> >> +int
>> >> +smb2_local_to_ucs2_bytes(const char *from, int len,
>> >> + const struct nls_table *codepage)
>> >> +{
>> >> + int charlen;
>> >> + int i;
>> >> + wchar_t wchar_to;
>> >> +
>> >> + if (from == NULL)
>> >> + return 0;
>
> ^^^^^^^^
> Are there really cases where you'll pass in a NULL pointer here?
Good catch, thanks!
>
>> >> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
>> >> + charlen = codepage->char2uni(from, len, &wchar_to);
> ^^^^
> This may result in an unaligned
> access. You should use
> put_unaligned to place this
> in the string.
We only count the length of new unicode string here - so, don't need
to put it somewhere.
>
>> >> + /* Failed conversion defaults to a question mark */
>> >> + if (charlen < 1)
>> >> + charlen = 1;
>> >> + }
>> >> + return 2 * i; /* UCS characters are two bytes */
>> >> +}
>> >> +
>> >> +/*
>> >> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
>> >> + * @src - source string
>> >> + * @maxlen - don't walk past this many bytes in the source string
>> >> + * @ucslen - the length of the allocated string in bytes (including null)
>> >> + * @codepage - source codepage
>> >> + *
>> >> + * Take a string convert it from the local codepage to UCS2 and
>> >> + * put it in a new buffer. Returns a pointer to the new string or NULL on
>> >> + * error.
>> >> + */
>> >> +__le16 *
>> >> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
>> >> + const struct nls_table *codepage)
>> >> +{
>> >> + int len;
>> >> + __le16 *dst;
>> >> +
>> >> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
>> >> + len += 2; /* NULL */
>> >> + dst = kmalloc(len, GFP_KERNEL);
>> >> + if (!dst) {
>> >> + *ucs_len = 0;
>> >> + return NULL;
>> >> + }
>> >> + cifs_strtoUCS(dst, src, maxlen, codepage);
>> >> + *ucs_len = len;
>> >> + return dst;
>> >> +}
>> >> +#endif /* CONFIG_CIFS_SMB2 */
>> >> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
>> >> index 6d02fd5..e00f677 100644
>> >> --- a/fs/cifs/cifs_unicode.h
>> >> +++ b/fs/cifs/cifs_unicode.h
>> >> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>> >>
>> >> #endif
>> >>
>> >> +#ifdef CONFIG_CIFS_SMB2
>> >> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
>> >> + const struct nls_table *codepage);
>> >> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
>> >> + int *ucs_len, const struct nls_table *cp);
>> >> +#endif /* CONFIG_CIFS_SMB2 */
>> >> +
>> >> #endif /* _CIFS_UNICODE_H */
>> >> --
>> >> 1.7.1
>> >>
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> >>
>> >
>> > Should these functions be renamed to *utf16* instead of *ucs*
>> > to reflect the unicode encoding used in cifs/smb2 protocol?
>>
>> Seems no problem to rename it.
>>
>> Jeff, Steve, thoughts? If no objections - I will rename *ucs* to *utf16*.
>>
> Yeah, now that I look over the NLS code, it does seem to be converting
> to UTF16 and not to UCS2. You should probably rename the existing *ucs*
> functions in cifs_unicode.c as well.
>
> Also, we should probably settle on a prefix for these that makes sense.
> These are only currently used by smb2 code, but they aren't truly
> smb2-specific. I'd name them cifs_* myself, but maybe something more
> neutral makes sense?
>
I think, cifs_* will be ok.
--
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-11-01 10:12 ` Jeff Layton
2011-11-01 13:52 ` Shirish Pargaonkar
@ 2012-01-12 17:22 ` Shirish Pargaonkar
[not found] ` <CADT32eJ7FMkQZiy4LjeEG3axvt99N7jFEod7-u2js1MnhVkc7Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-01-12 20:41 ` Shirish Pargaonkar
3 siblings, 1 reply; 75+ messages in thread
From: Shirish Pargaonkar @ 2012-01-12 17:22 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/cifs/cifs_unicode.h | 7 +++++
> 2 files changed, 68 insertions(+), 0 deletions(-)
>
> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> index 1b2e180..7f09423 100644
> --- a/fs/cifs/cifs_unicode.c
> +++ b/fs/cifs/cifs_unicode.c
> @@ -330,3 +330,64 @@ ctoUCS_out:
> return i;
> }
>
> +#ifdef CONFIG_CIFS_SMB2
> +/*
> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> + * @from - pointer to input string
> + * @maxbytes - don't go past this many bytes of input string
> + * @codepage - source codepage
> + *
> + * Walk a string and return the number of bytes that the string will
> + * be after being converted to the given charset, not including any null
> + * termination required. Don't walk past maxbytes in the source buffer.
> + */
> +
> +int
> +smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage)
> +{
> + int charlen;
> + int i;
> + wchar_t wchar_to;
> +
> + if (from == NULL)
> + return 0;
> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> + charlen = codepage->char2uni(from, len, &wchar_to);
Why call function char2uni? It either returns 1 or EINVAL.
If it returns EINVAL, charlen is set to 1. So either way charlen
will always be 1.
So why not just call strlen(from) to determine the length of the string?
> + /* Failed conversion defaults to a question mark */
> + if (charlen < 1)
> + charlen = 1;
> + }
> + return 2 * i; /* UCS characters are two bytes */
> +}
> +
> +/*
> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> + * @src - source string
> + * @maxlen - don't walk past this many bytes in the source string
> + * @ucslen - the length of the allocated string in bytes (including null)
> + * @codepage - source codepage
> + *
> + * Take a string convert it from the local codepage to UCS2 and
> + * put it in a new buffer. Returns a pointer to the new string or NULL on
> + * error.
> + */
> +__le16 *
> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> + const struct nls_table *codepage)
> +{
> + int len;
> + __le16 *dst;
> +
> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> + len += 2; /* NULL */
> + dst = kmalloc(len, GFP_KERNEL);
> + if (!dst) {
> + *ucs_len = 0;
> + return NULL;
> + }
> + cifs_strtoUCS(dst, src, maxlen, codepage);
> + *ucs_len = len;
> + return dst;
> +}
> +#endif /* CONFIG_CIFS_SMB2 */
> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> index 6d02fd5..e00f677 100644
> --- a/fs/cifs/cifs_unicode.h
> +++ b/fs/cifs/cifs_unicode.h
> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>
> #endif
>
> +#ifdef CONFIG_CIFS_SMB2
> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage);
> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> + int *ucs_len, const struct nls_table *cp);
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> #endif /* _CIFS_UNICODE_H */
> --
> 1.7.1
>
> --
> 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] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <CADT32eJ7FMkQZiy4LjeEG3axvt99N7jFEod7-u2js1MnhVkc7Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-01-12 18:42 ` Jeff Layton
2012-01-12 19:58 ` Shirish Pargaonkar
0 siblings, 1 reply; 75+ messages in thread
From: Jeff Layton @ 2012-01-12 18:42 UTC (permalink / raw)
To: Shirish Pargaonkar
Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Thu, 12 Jan 2012 11:22:35 -0600
Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> > From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >
> > Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> > Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> > ---
> > fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> > fs/cifs/cifs_unicode.h | 7 +++++
> > 2 files changed, 68 insertions(+), 0 deletions(-)
> >
> > diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> > index 1b2e180..7f09423 100644
> > --- a/fs/cifs/cifs_unicode.c
> > +++ b/fs/cifs/cifs_unicode.c
> > @@ -330,3 +330,64 @@ ctoUCS_out:
> > return i;
> > }
> >
> > +#ifdef CONFIG_CIFS_SMB2
> > +/*
> > + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> > + * @from - pointer to input string
> > + * @maxbytes - don't go past this many bytes of input string
> > + * @codepage - source codepage
> > + *
> > + * Walk a string and return the number of bytes that the string will
> > + * be after being converted to the given charset, not including any null
> > + * termination required. Don't walk past maxbytes in the source buffer.
> > + */
> > +
> > +int
> > +smb2_local_to_ucs2_bytes(const char *from, int len,
> > + const struct nls_table *codepage)
> > +{
> > + int charlen;
> > + int i;
> > + wchar_t wchar_to;
> > +
> > + if (from == NULL)
> > + return 0;
> > + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> > + charlen = codepage->char2uni(from, len, &wchar_to);
>
> Why call function char2uni? It either returns 1 or EINVAL.
> If it returns EINVAL, charlen is set to 1. So either way charlen
> will always be 1.
> So why not just call strlen(from) to determine the length of the string?
>
I thought char2uni returned the width of the character. That's not
necessarily going to be 1 in all cases.
> > + /* Failed conversion defaults to a question mark */
> > + if (charlen < 1)
> > + charlen = 1;
> > + }
> > + return 2 * i; /* UCS characters are two bytes */
> > +}
> > +
> > +/*
> > + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> > + * @src - source string
> > + * @maxlen - don't walk past this many bytes in the source string
> > + * @ucslen - the length of the allocated string in bytes (including null)
> > + * @codepage - source codepage
> > + *
> > + * Take a string convert it from the local codepage to UCS2 and
> > + * put it in a new buffer. Returns a pointer to the new string or NULL on
> > + * error.
> > + */
> > +__le16 *
> > +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> > + const struct nls_table *codepage)
> > +{
> > + int len;
> > + __le16 *dst;
> > +
> > + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> > + len += 2; /* NULL */
> > + dst = kmalloc(len, GFP_KERNEL);
> > + if (!dst) {
> > + *ucs_len = 0;
> > + return NULL;
> > + }
> > + cifs_strtoUCS(dst, src, maxlen, codepage);
> > + *ucs_len = len;
> > + return dst;
> > +}
> > +#endif /* CONFIG_CIFS_SMB2 */
> > diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> > index 6d02fd5..e00f677 100644
> > --- a/fs/cifs/cifs_unicode.h
> > +++ b/fs/cifs/cifs_unicode.h
> > @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
> >
> > #endif
> >
> > +#ifdef CONFIG_CIFS_SMB2
> > +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> > + const struct nls_table *codepage);
> > +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> > + int *ucs_len, const struct nls_table *cp);
> > +#endif /* CONFIG_CIFS_SMB2 */
> > +
> > #endif /* _CIFS_UNICODE_H */
> > --
> > 1.7.1
> >
> > --
> > 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
> --
> 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
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
2012-01-12 18:42 ` Jeff Layton
@ 2012-01-12 19:58 ` Shirish Pargaonkar
[not found] ` <CADT32eKc=Xq5G1cE+pye6h1dN6sjry+b7V0ze7CTMJXC8JCtwA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 75+ messages in thread
From: Shirish Pargaonkar @ 2012-01-12 19:58 UTC (permalink / raw)
To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs, linux-fsdevel, Steve French
On Thu, Jan 12, 2012 at 12:42 PM, Jeff Layton <jlayton@samba.org> wrote:
> On Thu, 12 Jan 2012 11:22:35 -0600
> Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote:
>
>> On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>> > From: Steve French <sfrench@us.ibm.com>
>> >
>> > Signed-off-by: Steve French <sfrench@us.ibm.com>
>> > Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
>> > ---
>> > fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
>> > fs/cifs/cifs_unicode.h | 7 +++++
>> > 2 files changed, 68 insertions(+), 0 deletions(-)
>> >
>> > diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
>> > index 1b2e180..7f09423 100644
>> > --- a/fs/cifs/cifs_unicode.c
>> > +++ b/fs/cifs/cifs_unicode.c
>> > @@ -330,3 +330,64 @@ ctoUCS_out:
>> > return i;
>> > }
>> >
>> > +#ifdef CONFIG_CIFS_SMB2
>> > +/*
>> > + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
>> > + * @from - pointer to input string
>> > + * @maxbytes - don't go past this many bytes of input string
>> > + * @codepage - source codepage
>> > + *
>> > + * Walk a string and return the number of bytes that the string will
>> > + * be after being converted to the given charset, not including any null
>> > + * termination required. Don't walk past maxbytes in the source buffer.
>> > + */
>> > +
>> > +int
>> > +smb2_local_to_ucs2_bytes(const char *from, int len,
>> > + const struct nls_table *codepage)
>> > +{
>> > + int charlen;
>> > + int i;
>> > + wchar_t wchar_to;
>> > +
>> > + if (from == NULL)
>> > + return 0;
>> > + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
>> > + charlen = codepage->char2uni(from, len, &wchar_to);
>>
>> Why call function char2uni? It either returns 1 or EINVAL.
>> If it returns EINVAL, charlen is set to 1. So either way charlen
>> will always be 1.
>> So why not just call strlen(from) to determine the length of the string?
>>
>
> I thought char2uni returned the width of the character. That's not
> necessarily going to be 1 in all cases.
>
It is very confusing. Does width of the character means width of the
unicode character? If so, should not it be the same for all unicode
characters? Or by width of the character, is it meant the width of
the encoding of a unicode character? If so, I do not see anywhere
in fs/nls direcotry any char2uni function returning width of a
utf16 encoding of a unicode character corrosponding to a character
within the native codepath
>> > + /* Failed conversion defaults to a question mark */
>> > + if (charlen < 1)
>> > + charlen = 1;
>> > + }
>> > + return 2 * i; /* UCS characters are two bytes */
>> > +}
>> > +
>> > +/*
>> > + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
>> > + * @src - source string
>> > + * @maxlen - don't walk past this many bytes in the source string
>> > + * @ucslen - the length of the allocated string in bytes (including null)
>> > + * @codepage - source codepage
>> > + *
>> > + * Take a string convert it from the local codepage to UCS2 and
>> > + * put it in a new buffer. Returns a pointer to the new string or NULL on
>> > + * error.
>> > + */
>> > +__le16 *
>> > +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
>> > + const struct nls_table *codepage)
>> > +{
>> > + int len;
>> > + __le16 *dst;
>> > +
>> > + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
>> > + len += 2; /* NULL */
>> > + dst = kmalloc(len, GFP_KERNEL);
>> > + if (!dst) {
>> > + *ucs_len = 0;
>> > + return NULL;
>> > + }
>> > + cifs_strtoUCS(dst, src, maxlen, codepage);
>> > + *ucs_len = len;
>> > + return dst;
>> > +}
>> > +#endif /* CONFIG_CIFS_SMB2 */
>> > diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
>> > index 6d02fd5..e00f677 100644
>> > --- a/fs/cifs/cifs_unicode.h
>> > +++ b/fs/cifs/cifs_unicode.h
>> > @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>> >
>> > #endif
>> >
>> > +#ifdef CONFIG_CIFS_SMB2
>> > +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
>> > + const struct nls_table *codepage);
>> > +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
>> > + int *ucs_len, const struct nls_table *cp);
>> > +#endif /* CONFIG_CIFS_SMB2 */
>> > +
>> > #endif /* _CIFS_UNICODE_H */
>> > --
>> > 1.7.1
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> --
> Jeff Layton <jlayton@samba.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (2 preceding siblings ...)
2012-01-12 17:22 ` Shirish Pargaonkar
@ 2012-01-12 20:41 ` Shirish Pargaonkar
3 siblings, 0 replies; 75+ messages in thread
From: Shirish Pargaonkar @ 2012-01-12 20:41 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/cifs/cifs_unicode.h | 7 +++++
> 2 files changed, 68 insertions(+), 0 deletions(-)
>
> diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> index 1b2e180..7f09423 100644
> --- a/fs/cifs/cifs_unicode.c
> +++ b/fs/cifs/cifs_unicode.c
> @@ -330,3 +330,64 @@ ctoUCS_out:
> return i;
> }
>
> +#ifdef CONFIG_CIFS_SMB2
> +/*
> + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> + * @from - pointer to input string
> + * @maxbytes - don't go past this many bytes of input string
> + * @codepage - source codepdo
age
> + *
> + * Walk a string and return the number of bytes that the string will
> + * be after being converted to the given charset, not including any null
> + * termination required. Don't walk past maxbytes in the source buffer.
> + */
> +
> +int
> +smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage)
since utf16 encodings are not more than 2 bytes, this function
can just return 2 * (strlen(from) + 1) perhaps?
> +{
> + int charlen;
> + int i;
> + wchar_t wchar_to;
> +
> + if (from == NULL)
> + return 0;
> + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> + charlen = codepage->char2uni(from, len, &wchar_to);
> + /* Failed conversion defaults to a question mark */
> + if (charlen < 1)
> + charlen = 1;
> + }
> + return 2 * i; /* UCS characters are two bytes */
> +}
> +
> +/*
> + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> + * @src - source string
> + * @maxlen - don't walk past this many bytes in the source string
> + * @ucslen - the length of the allocated string in bytes (including null)
> + * @codepage - source codepage
> + *
> + * Take a string convert it from the local codepage to UCS2 and
> + * put it in a new buffer. Returns a pointer to the new string or NULL on
> + * error.
> + */
> +__le16 *
> +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> + const struct nls_table *codepage)
> +{
> + int len;
> + __le16 *dst;
> +
> + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> + len += 2; /* NULL */
> + dst = kmalloc(len, GFP_KERNEL);
> + if (!dst) {
> + *ucs_len = 0;
> + return NULL;
> + }
> + cifs_strtoUCS(dst, src, maxlen, codepage);
> + *ucs_len = len;
> + return dst;
> +}
> +#endif /* CONFIG_CIFS_SMB2 */
> diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> index 6d02fd5..e00f677 100644
> --- a/fs/cifs/cifs_unicode.h
> +++ b/fs/cifs/cifs_unicode.h
> @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
>
> #endif
>
> +#ifdef CONFIG_CIFS_SMB2
> +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> + const struct nls_table *codepage);
> +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> + int *ucs_len, const struct nls_table *cp);
> +#endif /* CONFIG_CIFS_SMB2 */
> +
> #endif /* _CIFS_UNICODE_H */
> --
> 1.7.1
>
> --
> 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] 75+ messages in thread
* Re: [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2
[not found] ` <CADT32eKc=Xq5G1cE+pye6h1dN6sjry+b7V0ze7CTMJXC8JCtwA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-01-12 20:48 ` Jeff Layton
0 siblings, 0 replies; 75+ messages in thread
From: Jeff Layton @ 2012-01-12 20:48 UTC (permalink / raw)
To: Shirish Pargaonkar
Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Steve French
On Thu, 12 Jan 2012 13:58:50 -0600
Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Thu, Jan 12, 2012 at 12:42 PM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> > On Thu, 12 Jan 2012 11:22:35 -0600
> > Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >
> >> On Fri, Oct 28, 2011 at 2:54 PM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
> >> > From: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >> >
> >> > Signed-off-by: Steve French <sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> >> > Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >> > ---
> >> > fs/cifs/cifs_unicode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> > fs/cifs/cifs_unicode.h | 7 +++++
> >> > 2 files changed, 68 insertions(+), 0 deletions(-)
> >> >
> >> > diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
> >> > index 1b2e180..7f09423 100644
> >> > --- a/fs/cifs/cifs_unicode.c
> >> > +++ b/fs/cifs/cifs_unicode.c
> >> > @@ -330,3 +330,64 @@ ctoUCS_out:
> >> > return i;
> >> > }
> >> >
> >> > +#ifdef CONFIG_CIFS_SMB2
> >> > +/*
> >> > + * smb2_local_to_ucs2_bytes - how long will a string be after conversion?
> >> > + * @from - pointer to input string
> >> > + * @maxbytes - don't go past this many bytes of input string
> >> > + * @codepage - source codepage
> >> > + *
> >> > + * Walk a string and return the number of bytes that the string will
> >> > + * be after being converted to the given charset, not including any null
> >> > + * termination required. Don't walk past maxbytes in the source buffer.
> >> > + */
> >> > +
> >> > +int
> >> > +smb2_local_to_ucs2_bytes(const char *from, int len,
> >> > + const struct nls_table *codepage)
> >> > +{
> >> > + int charlen;
> >> > + int i;
> >> > + wchar_t wchar_to;
> >> > +
> >> > + if (from == NULL)
> >> > + return 0;
> >> > + for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
> >> > + charlen = codepage->char2uni(from, len, &wchar_to);
> >>
> >> Why call function char2uni? It either returns 1 or EINVAL.
> >> If it returns EINVAL, charlen is set to 1. So either way charlen
> >> will always be 1.
> >> So why not just call strlen(from) to determine the length of the string?
> >>
> >
> > I thought char2uni returned the width of the character. That's not
> > necessarily going to be 1 in all cases.
> >
>
> It is very confusing. Does width of the character means width of the
> unicode character? If so, should not it be the same for all unicode
> characters? Or by width of the character, is it meant the width of
> the encoding of a unicode character? If so, I do not see anywhere
> in fs/nls direcotry any char2uni function returning width of a
> utf16 encoding of a unicode character corrosponding to a character
> within the native codepath
>
>
I meant the width of the original character. The result is always going
to be 2 bytes, but the original character can be up to 4 bytes long in
the case of UTF-8.
I think Pavel is quite correct to call char2uni this way in order to
determine the length of the resulting string.
> >> > + /* Failed conversion defaults to a question mark */
> >> > + if (charlen < 1)
> >> > + charlen = 1;
> >> > + }
> >> > + return 2 * i; /* UCS characters are two bytes */
> >> > +}
> >> > +
> >> > +/*
> >> > + * smb2_strndup_to_ucs - copy a string to wire format from the local codepage
> >> > + * @src - source string
> >> > + * @maxlen - don't walk past this many bytes in the source string
> >> > + * @ucslen - the length of the allocated string in bytes (including null)
> >> > + * @codepage - source codepage
> >> > + *
> >> > + * Take a string convert it from the local codepage to UCS2 and
> >> > + * put it in a new buffer. Returns a pointer to the new string or NULL on
> >> > + * error.
> >> > + */
> >> > +__le16 *
> >> > +smb2_strndup_to_ucs(const char *src, const int maxlen, int *ucs_len,
> >> > + const struct nls_table *codepage)
> >> > +{
> >> > + int len;
> >> > + __le16 *dst;
> >> > +
> >> > + len = smb2_local_to_ucs2_bytes(src, maxlen, codepage);
> >> > + len += 2; /* NULL */
> >> > + dst = kmalloc(len, GFP_KERNEL);
> >> > + if (!dst) {
> >> > + *ucs_len = 0;
> >> > + return NULL;
> >> > + }
> >> > + cifs_strtoUCS(dst, src, maxlen, codepage);
> >> > + *ucs_len = len;
> >> > + return dst;
> >> > +}
> >> > +#endif /* CONFIG_CIFS_SMB2 */
> >> > diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
> >> > index 6d02fd5..e00f677 100644
> >> > --- a/fs/cifs/cifs_unicode.h
> >> > +++ b/fs/cifs/cifs_unicode.h
> >> > @@ -380,4 +380,11 @@ UniStrlwr(register wchar_t *upin)
> >> >
> >> > #endif
> >> >
> >> > +#ifdef CONFIG_CIFS_SMB2
> >> > +extern int smb2_local_to_ucs2_bytes(const char *from, int len,
> >> > + const struct nls_table *codepage);
> >> > +extern __le16 *smb2_strndup_to_ucs(const char *src, const int maxlen,
> >> > + int *ucs_len, const struct nls_table *cp);
> >> > +#endif /* CONFIG_CIFS_SMB2 */
> >> > +
> >> > #endif /* _CIFS_UNICODE_H */
> >> > --
> >> > 1.7.1
> >> >
> >> > --
> >> > 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
> >> --
> >> 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
> >
> >
> > --
> > 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
--
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
^ permalink raw reply [flat|nested] 75+ messages in thread
end of thread, other threads:[~2012-01-12 20:48 UTC | newest]
Thread overview: 75+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-28 19:54 [PATCH v2 00/53] SMB2 protocol support for CIFS kernel module Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 02/53] CIFS: Allow SMB2 statistics to be tracked Pavel Shilovsky
2011-10-29 4:48 ` Jeff Layton
2011-10-29 5:12 ` Steve French
[not found] ` <CAH2r5mtpckA75LEAynsPLVsPfr7U0wnYAyZ1uKeK2VU9F1CGeQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-29 5:32 ` Jeff Layton
[not found] ` <20111029004814.41340503-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2011-10-29 19:44 ` Pavel Shilovsky
[not found] ` <CAKywueQwBwR-HZtv6gQv32kt4+2qycS7vq5KDLiE3xw3_9=wPA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-30 2:12 ` Jeff Layton
[not found] ` <20111029221251.5fba1444-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2011-10-30 2:52 ` Steve French
2011-10-28 19:54 ` [PATCH v2 03/53] CIFS: Check for smb2 vs. cifs in find_tcp_session Pavel Shilovsky
[not found] ` <1319831704-3572-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-29 4:40 ` Jeff Layton
[not found] ` <20111029004046.2bf8e111-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2011-10-29 19:55 ` Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 05/53] CIFS: wait_for_free_request needs to wait on credits returned by server (for SMB2) Pavel Shilovsky
[not found] ` <1319831704-3572-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-29 15:35 ` Jeff Layton
2011-10-29 20:00 ` Pavel Shilovsky
[not found] ` <CAKywueSGDSw33L4_a7W6D7gM_PH9uy3xTQ6=8zgAimGhz5=UfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-30 2:41 ` Jeff Layton
2011-10-28 19:54 ` [PATCH v2 07/53] CIFS: Add structure definitions for SMB2 PDUs Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 09/53] CIFS: Allocating SMB2 mids (multiplex identifier structures) Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 15/53] CIFS: Make demultiplex_thread work with SMB2 code Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 16/53] CIFS: Get mount/umount work with SMB2 protocol Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 18/53] CIFS: Add SMB2 inode/dentry ops structures Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 19/53] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 22/53] CIFS: Add SMB2 support for open/close file operations Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 23/53] CIFS: Add SMB2 support for reopen file operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 25/53] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 26/53] CIFS: Add address space ops structures for SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 28/53] CIFS: Add write related address space operations " Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 30/53] CIFS: Temporarily disable set inode info " Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 31/53] CIFS: Add writepages support " Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 32/53] CIFS: Add readpages " Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 33/53] CIFS: Add echo request " Pavel Shilovsky
[not found] ` <1319831704-3572-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-28 19:54 ` [PATCH v2 01/53] CIFS: Update cifs global structures to handle smb2 sessions Pavel Shilovsky
[not found] ` <1319831704-3572-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-29 4:54 ` Jeff Layton
2011-10-28 19:54 ` [PATCH v2 04/53] CIFS: Do not try to dump cifs mids from " Pavel Shilovsky
[not found] ` <1319831704-3572-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-29 5:05 ` Jeff Layton
2011-10-28 19:54 ` [PATCH v2 06/53] CIFS: Add missing unicode handling routines needed by smb2 Pavel Shilovsky
[not found] ` <1319831704-3572-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-11-01 10:12 ` Jeff Layton
2011-11-01 13:52 ` Shirish Pargaonkar
2011-12-29 15:01 ` Pavel Shilovsky
2011-12-30 12:42 ` Jeff Layton
2012-01-12 10:47 ` Pavel Shilovsky
2012-01-12 17:22 ` Shirish Pargaonkar
[not found] ` <CADT32eJ7FMkQZiy4LjeEG3axvt99N7jFEod7-u2js1MnhVkc7Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-01-12 18:42 ` Jeff Layton
2012-01-12 19:58 ` Shirish Pargaonkar
[not found] ` <CADT32eKc=Xq5G1cE+pye6h1dN6sjry+b7V0ze7CTMJXC8JCtwA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-01-12 20:48 ` Jeff Layton
2012-01-12 20:41 ` Shirish Pargaonkar
2011-10-28 19:54 ` [PATCH v2 10/53] CIFS: Add routines to free SMB2 mids Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 11/53] CIFS: Add sync_smb2_mid_result Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 13/53] CIFS: Add SMB2 transport routines Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 14/53] CIFS: Expand cifs mid structure to keep SMB2 related fields Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 17/53] CIFS: Simplify SMB2 query info Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 20/53] CIFS: Add SMB2 support for rmdir operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 21/53] CIFS: Add SMB2 support for unlink operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 24/53] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 27/53] CIFS: Add read related address space operations for SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 29/53] CIFS: Respect max buf size for SMB2 read and write Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 34/53] [CIFS] Add SMB2 support for cifs_get_file_info Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 35/53] CIFS: Add SMB2 support for create operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 36/53] CIFS: Add readdir support for SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 37/53] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 38/53] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 40/53] CIFS: Add NTLMSSP sec type to defaults Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 41/53] CIFS: Disable SMB2.1 protocol negotiating Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 43/53] CIFS: Process STATUS_PENDING responses for SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 44/53] CIFS: Request SMB2.1 leases Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 45/53] CIFS: Process oplock/lease break for SMB2/2.1 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 47/53] CIFS: Enable signing in SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 48/53] CIFS: Process signing for SMB2_logoff Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 49/53] CIFS: Introduce SMB2 Kconfig option Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 50/53] CIFS: Introduce smb2 mounts as vers=2 Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 53/53] CIFS: Disable lock call for SMB2 since we don't support it Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 39/53] CIFS: Add SMB2 support for flush operation Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 42/53] CIFS: Process oplocks for SMB2 Pavel Shilovsky
2011-10-28 19:54 ` [PATCH v2 46/53] CIFS: Add strictcache i/o " Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 51/53] CIFS: Change Makefile to support CONFIG_CIFS_SMB2 Pavel Shilovsky
2011-10-28 19:55 ` [PATCH v2 52/53] CIFS: Add statfs support for SMB2 Pavel Shilovsky
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).