Commit 9093ba53 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  cifs: fix up CIFSSMBEcho for unaligned access
  cifs: fix unaligned accesses in cifsConvertToUCS
  cifs: clean up unaligned accesses in cifs_unicode.c
  cifs: fix unaligned access in check2ndT2 and coalesce_t2
  cifs: clean up unaligned accesses in validate_t2
  cifs: use get/put_unaligned functions to access ByteCount
  cifs: move time field in cifsInodeInfo
  cifs: TCP_Server_Info diet
  CIFS: Implement cifs_strict_readv (try #4)
  CIFS: Implement cifs_file_strict_mmap (try #2)
  CIFS: Implement cifs_strict_fsync
  CIFS: Make cifsFileInfo_put work with strict cache mode
parents ebe0d805 99d86c8f
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
struct cifs_sb_info { struct cifs_sb_info {
struct rb_root tlink_tree; struct rb_root tlink_tree;
......
...@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, ...@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
int charlen, outlen = 0; int charlen, outlen = 0;
int maxwords = maxbytes / 2; int maxwords = maxbytes / 2;
char tmp[NLS_MAX_CHARSET_SIZE]; char tmp[NLS_MAX_CHARSET_SIZE];
__u16 ftmp;
for (i = 0; i < maxwords && from[i]; i++) { for (i = 0; i < maxwords; i++) {
charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, ftmp = get_unaligned_le16(&from[i]);
NLS_MAX_CHARSET_SIZE); if (ftmp == 0)
break;
charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
if (charlen > 0) if (charlen > 0)
outlen += charlen; outlen += charlen;
else else
...@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, ...@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
} }
/* /*
* cifs_mapchar - convert a little-endian char to proper char in codepage * cifs_mapchar - convert a host-endian char to proper char in codepage
* @target - where converted character should be copied * @target - where converted character should be copied
* @src_char - 2 byte little-endian source character * @src_char - 2 byte host-endian source character
* @cp - codepage to which character should be converted * @cp - codepage to which character should be converted
* @mapchar - should character be mapped according to mapchars mount option? * @mapchar - should character be mapped according to mapchars mount option?
* *
...@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, ...@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
*/ */
static int static int
cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
bool mapchar) bool mapchar)
{ {
int len = 1; int len = 1;
...@@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, ...@@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
* build_path_from_dentry are modified, as they use slash as * build_path_from_dentry are modified, as they use slash as
* separator. * separator.
*/ */
switch (le16_to_cpu(src_char)) { switch (src_char) {
case UNI_COLON: case UNI_COLON:
*target = ':'; *target = ':';
break; break;
...@@ -109,8 +113,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, ...@@ -109,8 +113,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
return len; return len;
cp_convert: cp_convert:
len = cp->uni2char(le16_to_cpu(src_char), target, len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
NLS_MAX_CHARSET_SIZE);
if (len <= 0) { if (len <= 0) {
*target = '?'; *target = '?';
len = 1; len = 1;
...@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, ...@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
int nullsize = nls_nullsize(codepage); int nullsize = nls_nullsize(codepage);
int fromwords = fromlen / 2; int fromwords = fromlen / 2;
char tmp[NLS_MAX_CHARSET_SIZE]; char tmp[NLS_MAX_CHARSET_SIZE];
__u16 ftmp;
/* /*
* because the chars can be of varying widths, we need to take care * because the chars can be of varying widths, we need to take care
...@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, ...@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
*/ */
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
for (i = 0; i < fromwords && from[i]; i++) { for (i = 0; i < fromwords; i++) {
ftmp = get_unaligned_le16(&from[i]);
if (ftmp == 0)
break;
/* /*
* check to see if converting this character might make the * check to see if converting this character might make the
* conversion bleed into the null terminator * conversion bleed into the null terminator
*/ */
if (outlen >= safelen) { if (outlen >= safelen) {
charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
if ((outlen + charlen) > (tolen - nullsize)) if ((outlen + charlen) > (tolen - nullsize))
break; break;
} }
/* put converted char into 'to' buffer */ /* put converted char into 'to' buffer */
charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
outlen += charlen; outlen += charlen;
} }
...@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, ...@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
{ {
int charlen; int charlen;
int i; int i;
wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */ wchar_t wchar_to; /* needed to quiet sparse */
for (i = 0; len && *from; i++, from += charlen, len -= charlen) { for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
charlen = codepage->char2uni(from, len, &wchar_to);
/* works for 2.4.0 kernel or later */
charlen = codepage->char2uni(from, len, &wchar_to[i]);
if (charlen < 1) { if (charlen < 1) {
cERROR(1, "strtoUCS: char2uni of %d returned %d", cERROR(1, "strtoUCS: char2uni of 0x%x returned %d",
(int)*from, charlen); *from, charlen);
/* A question mark */ /* A question mark */
to[i] = cpu_to_le16(0x003f); wchar_to = 0x003f;
charlen = 1; charlen = 1;
} else }
to[i] = cpu_to_le16(wchar_to[i]); put_unaligned_le16(wchar_to, &to[i]);
} }
to[i] = 0; put_unaligned_le16(0, &to[i]);
return i; return i;
} }
...@@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, ...@@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
return dst; return dst;
} }
/*
* Convert 16 bit Unicode pathname to wire format from string in current code
* page. Conversion may involve remapping up the six characters that are
* only legal in POSIX-like OS (if they are present in the string). Path
* names are little endian 16 bit Unicode on the wire
*/
int
cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
const struct nls_table *cp, int mapChars)
{
int i, j, charlen;
int len_remaining = maxlen;
char src_char;
__u16 temp;
if (!mapChars)
return cifs_strtoUCS(target, source, PATH_MAX, cp);
for (i = 0, j = 0; i < maxlen; j++) {
src_char = source[i];
switch (src_char) {
case 0:
put_unaligned_le16(0, &target[j]);
goto ctoUCS_out;
case ':':
temp = UNI_COLON;
break;
case '*':
temp = UNI_ASTERIK;
break;
case '?':
temp = UNI_QUESTION;
break;
case '<':
temp = UNI_LESSTHAN;
break;
case '>':
temp = UNI_GRTRTHAN;
break;
case '|':
temp = UNI_PIPE;
break;
/*
* FIXME: We can not handle remapping backslash (UNI_SLASH)
* until all the calls to build_path_from_dentry are modified,
* as they use backslash as separator.
*/
default:
charlen = cp->char2uni(source+i, len_remaining,
&temp);
/*
* if no match, use question mark, which at least in
* some cases serves as wild card
*/
if (charlen < 1) {
temp = 0x003f;
charlen = 1;
}
len_remaining -= charlen;
/*
* character may take more than one byte in the source
* string, but will take exactly two bytes in the
* target string
*/
i += charlen;
continue;
}
put_unaligned_le16(temp, &target[j]);
i++; /* move to next char in source string */
len_remaining--;
}
ctoUCS_out:
return i;
}
...@@ -733,6 +733,25 @@ const struct file_operations cifs_file_ops = { ...@@ -733,6 +733,25 @@ const struct file_operations cifs_file_ops = {
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_strict_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_strict_readv,
.aio_write = cifs_file_aio_write,
.open = cifs_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 cifs_file_direct_ops = { const struct file_operations cifs_file_direct_ops = {
/* no aio, no readv - /* no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */ BB reevaluate whether they can be done with directio, no cache */
...@@ -751,6 +770,7 @@ const struct file_operations cifs_file_direct_ops = { ...@@ -751,6 +770,7 @@ const struct file_operations cifs_file_direct_ops = {
.llseek = cifs_llseek, .llseek = cifs_llseek,
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_nobrl_ops = { const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
...@@ -769,6 +789,24 @@ const struct file_operations cifs_file_nobrl_ops = { ...@@ -769,6 +789,24 @@ const struct file_operations cifs_file_nobrl_ops = {
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_strict_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_strict_readv,
.aio_write = cifs_file_aio_write,
.open = cifs_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 cifs_file_direct_nobrl_ops = { const struct file_operations cifs_file_direct_nobrl_ops = {
/* no mmap, no aio, no readv - /* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */ BB reevaluate whether they can be done with directio, no cache */
......
...@@ -61,6 +61,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *, ...@@ -61,6 +61,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *); struct dentry *);
extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_file(struct file *filp);
extern int cifs_revalidate_dentry(struct dentry *); extern int cifs_revalidate_dentry(struct dentry *);
extern void cifs_invalidate_mapping(struct inode *inode);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *); extern int cifs_setattr(struct dentry *, struct iattr *);
...@@ -72,19 +73,25 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations; ...@@ -72,19 +73,25 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations;
/* Functions related to files and directories */ /* Functions related to files and directories */
extern const struct file_operations cifs_file_ops; extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
extern const struct file_operations cifs_file_nobrl_ops; extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */ extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */
extern const struct file_operations cifs_file_direct_nobrl_ops;
extern const struct file_operations cifs_file_strict_nobrl_ops;
extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_read(struct file *file, char __user *read_data, extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
size_t read_size, loff_t *poffset); size_t read_size, loff_t *poffset);
extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t *poffset); size_t write_size, loff_t *poffset);
extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, int); extern int cifs_fsync(struct file *, int);
extern int cifs_strict_fsync(struct file *, int);
extern int cifs_flush(struct file *, fl_owner_t id); 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_mmap(struct file * , struct vm_area_struct *);
extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops; extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
......
...@@ -161,6 +161,7 @@ struct TCP_Server_Info { ...@@ -161,6 +161,7 @@ struct TCP_Server_Info {
int srv_count; /* reference counter */ int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */ /* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
enum statusEnum tcpStatus; /* what we think the status is */
char *hostname; /* hostname portion of UNC string */ char *hostname; /* hostname portion of UNC string */
struct socket *ssocket; struct socket *ssocket;
struct sockaddr_storage dstaddr; struct sockaddr_storage dstaddr;
...@@ -168,25 +169,16 @@ struct TCP_Server_Info { ...@@ -168,25 +169,16 @@ struct TCP_Server_Info {
wait_queue_head_t response_q; wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
struct list_head pending_mid_q; struct list_head pending_mid_q;
void *Server_NlsInfo; /* BB - placeholder for future NLS info */
unsigned short server_codepage; /* codepage for the server */
enum protocolEnum protocolType;
char versionMajor;
char versionMinor;
bool svlocal:1; /* local server or remote */
bool noblocksnd; /* use blocking sendmsg */ bool noblocksnd; /* use blocking sendmsg */
bool noautotune; /* do not autotune send buf sizes */ bool noautotune; /* do not autotune send buf sizes */
bool tcp_nodelay; bool tcp_nodelay;
atomic_t inFlight; /* number of requests on the wire to server */ atomic_t inFlight; /* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2
atomic_t inSend; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#endif
enum statusEnum tcpStatus; /* what we think the status is */
struct mutex srv_mutex; struct mutex srv_mutex;
struct task_struct *tsk; struct task_struct *tsk;
char server_GUID[16]; char server_GUID[16];
char secMode; char secMode;
bool session_estab; /* mark when very first sess is established */
u16 dialect; /* dialect index that server chose */
enum securityEnum secType; enum securityEnum secType;
unsigned int maxReq; /* Clients should submit no more */ unsigned int maxReq; /* Clients should submit no more */
/* than maxReq distinct unanswered SMBs to the server when using */ /* than maxReq distinct unanswered SMBs to the server when using */
...@@ -199,8 +191,6 @@ struct TCP_Server_Info { ...@@ -199,8 +191,6 @@ struct TCP_Server_Info {
unsigned int max_vcs; /* maximum number of smb sessions, at least unsigned int max_vcs; /* maximum number of smb sessions, at least
those that can be specified uniquely with those that can be specified uniquely with
vcnumbers */ vcnumbers */
char sessid[4]; /* unique token id for this session */
/* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */ int capabilities; /* allow selective disabling of caps by smb sess */
int timeAdj; /* Adjust for difference in server time zone in sec */ int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */ __u16 CurrentMid; /* multiplex id - rotating counter */
...@@ -210,18 +200,20 @@ struct TCP_Server_Info { ...@@ -210,18 +200,20 @@ struct TCP_Server_Info {
__u32 sequence_number; /* for signing, protected by srv_mutex */ __u32 sequence_number; /* for signing, protected by srv_mutex */
struct session_key session_key; struct session_key session_key;
unsigned long lstrp; /* when we got last response from this server */ unsigned long lstrp; /* when we got last response from this server */
u16 dialect; /* dialect index that server chose */
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
/* extended security flavors that server supports */ /* extended security flavors that server supports */
bool sec_ntlmssp; /* supports NTLMSSP */
bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_kerberos; /* supports plain Kerberos */ bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */
bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_ntlmssp; /* supports NTLMSSP */
bool session_estab; /* mark when very first sess is established */
struct delayed_work echo; /* echo ping workqueue job */ struct delayed_work echo; /* echo ping workqueue job */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */ struct fscache_cookie *fscache; /* client index cache cookie */
#endif #endif
#ifdef CONFIG_CIFS_STATS2
atomic_t inSend; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#endif
}; };
/* /*
...@@ -447,11 +439,11 @@ struct cifsInodeInfo { ...@@ -447,11 +439,11 @@ struct cifsInodeInfo {
/* BB add in lists for dirty pages i.e. write caching info for oplock */ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
unsigned long time; /* jiffies of last update/check of inode */ bool clientCanCacheRead; /* read oplock */
bool clientCanCacheRead:1; /* read oplock */ bool clientCanCacheAll; /* read and writebehind oplock */
bool clientCanCacheAll:1; /* read and writebehind oplock */ bool delete_pending; /* DELETE_ON_CLOSE is set */
bool delete_pending:1; /* DELETE_ON_CLOSE is set */ bool invalid_mapping; /* pagecache is invalid */
bool invalid_mapping:1; /* pagecache is invalid */ unsigned long time; /* jiffies of last update of inode */
u64 server_eof; /* current file size on server */ u64 server_eof; /* current file size on server */
u64 uniqueid; /* server inode number */ u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */ u64 createtime; /* creation time on server */
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define _CIFSPDU_H #define _CIFSPDU_H
#include <net/sock.h> #include <net/sock.h>
#include <asm/unaligned.h>
#include "smbfsctl.h" #include "smbfsctl.h"
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
...@@ -426,11 +427,49 @@ struct smb_hdr { ...@@ -426,11 +427,49 @@ struct smb_hdr {
__u16 Mid; __u16 Mid;
__u8 WordCount; __u8 WordCount;
} __attribute__((packed)); } __attribute__((packed));
/* given a pointer to an smb_hdr retrieve the value of byte count */
#define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) /* given a pointer to an smb_hdr retrieve a char pointer to the byte count */
#define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) #define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \
(2 * (smb_var)->WordCount))
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */ /* given a pointer to an smb_hdr retrieve the pointer to the byte area */
#define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2) #define pByteArea(smb_var) (BCC(smb_var) + 2)
/* get the converted ByteCount for a SMB packet and return it */
static inline __u16
get_bcc(struct smb_hdr *hdr)
{
__u16 *bc_ptr = (__u16 *)BCC(hdr);
return get_unaligned(bc_ptr);
}
/* get the unconverted ByteCount for a SMB packet and return it */
static inline __u16
get_bcc_le(struct smb_hdr *hdr)
{
__le16 *bc_ptr = (__le16 *)BCC(hdr);
return get_unaligned_le16(bc_ptr);
}
/* set the ByteCount for a SMB packet in host-byte order */
static inline void
put_bcc(__u16 count, struct smb_hdr *hdr)
{
__u16 *bc_ptr = (__u16 *)BCC(hdr);
put_unaligned(count, bc_ptr);
}
/* set the ByteCount for a SMB packet in little-endian */
static inline void
put_bcc_le(__u16 count, struct smb_hdr *hdr)
{
__le16 *bc_ptr = (__le16 *)BCC(hdr);
put_unaligned_le16(count, bc_ptr);
}
/* /*
* Computer Name Length (since Netbios name was length 16 with last byte 0x20) * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
......
...@@ -331,37 +331,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, ...@@ -331,37 +331,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
static int validate_t2(struct smb_t2_rsp *pSMB) static int validate_t2(struct smb_t2_rsp *pSMB)
{ {
int rc = -EINVAL; unsigned int total_size;
int total_size;
char *pBCC; /* check for plausible wct */
if (pSMB->hdr.WordCount < 10)
goto vt2_err;
/* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */ /* check for parm and data offset going beyond end of smb */
if (pSMB->hdr.WordCount >= 10) { if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
(le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { goto vt2_err;
/* check that bcc is at least as big as parms + data */ /* check that bcc is at least as big as parms + data */
/* check that bcc is less than negotiated smb buffer */ /* check that bcc is less than negotiated smb buffer */
total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
if (total_size < 512) { if (total_size >= 512)
total_size += goto vt2_err;
le16_to_cpu(pSMB->t2_rsp.DataCount);
/* BCC le converted in SendReceive */ total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
pBCC = (pSMB->hdr.WordCount * 2) + if (total_size > get_bcc(&pSMB->hdr) ||
sizeof(struct smb_hdr) + total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
(char *)pSMB; goto vt2_err;
if ((total_size <= (*(u16 *)pBCC)) &&
(total_size <
CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
return 0; return 0;
} vt2_err:
}
}
}
cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
sizeof(struct smb_t2_rsp) + 16); sizeof(struct smb_t2_rsp) + 16);
return rc; return -EINVAL;
} }
int int
CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
{ {
...@@ -452,7 +450,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) ...@@ -452,7 +450,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
/* even though we do not use raw we might as well set this /* even though we do not use raw we might as well set this
accurately, in case we ever find a need for it */ accurately, in case we ever find a need for it */
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
...@@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) ...@@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->capabilities = le32_to_cpu(pSMBr->Capabilities);
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
server->timeAdj *= 60; server->timeAdj *= 60;
...@@ -737,9 +733,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server) ...@@ -737,9 +733,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
/* set up echo request */ /* set up echo request */
smb->hdr.Tid = cpu_to_le16(0xffff); smb->hdr.Tid = cpu_to_le16(0xffff);
smb->hdr.WordCount = cpu_to_le16(1); smb->hdr.WordCount = 1;
smb->EchoCount = cpu_to_le16(1); put_unaligned_le16(1, &smb->EchoCount);
smb->ByteCount = cpu_to_le16(1); put_bcc_le(1, &smb->hdr);
smb->Data[0] = 'a'; smb->Data[0] = 'a';
smb->hdr.smb_buf_length += 3; smb->hdr.smb_buf_length += 3;
...@@ -5611,7 +5607,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, ...@@ -5611,7 +5607,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
} }
/* make sure list_len doesn't go past end of SMB */ /* make sure list_len doesn't go past end of SMB */
end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
if ((char *)ea_response_data + list_len > end_of_smb) { if ((char *)ea_response_data + list_len > end_of_smb) {
cFYI(1, "EA list appears to go beyond SMB"); cFYI(1, "EA list appears to go beyond SMB");
rc = -EIO; rc = -EIO;
......
...@@ -232,9 +232,8 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -232,9 +232,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
{ {
struct smb_t2_rsp *pSMBt; struct smb_t2_rsp *pSMBt;
int total_data_size;
int data_in_this_rsp;
int remaining; int remaining;
__u16 total_data_size, data_in_this_rsp;
if (pSMB->Command != SMB_COM_TRANSACTION2) if (pSMB->Command != SMB_COM_TRANSACTION2)
return 0; return 0;
...@@ -248,8 +247,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) ...@@ -248,8 +247,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
pSMBt = (struct smb_t2_rsp *)pSMB; pSMBt = (struct smb_t2_rsp *)pSMB;
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
remaining = total_data_size - data_in_this_rsp; remaining = total_data_size - data_in_this_rsp;
...@@ -275,21 +274,18 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -275,21 +274,18 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
{ {
struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
int total_data_size;
int total_in_buf;
int remaining;
int total_in_buf2;
char *data_area_of_target; char *data_area_of_target;
char *data_area_of_buf2; char *data_area_of_buf2;
__u16 byte_count; int remaining;
__u16 byte_count, total_data_size, total_in_buf, total_in_buf2;
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { if (total_data_size !=
get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount))
cFYI(1, "total data size of primary and secondary t2 differ"); cFYI(1, "total data size of primary and secondary t2 differ");
}
total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
remaining = total_data_size - total_in_buf; remaining = total_data_size - total_in_buf;
...@@ -299,28 +295,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -299,28 +295,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
if (remaining == 0) /* nothing to do, ignore */ if (remaining == 0) /* nothing to do, ignore */
return 0; return 0;
total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount);
if (remaining < total_in_buf2) { if (remaining < total_in_buf2) {
cFYI(1, "transact2 2nd response contains too much data"); cFYI(1, "transact2 2nd response contains too much data");
} }
/* find end of first SMB data area */ /* find end of first SMB data area */
data_area_of_target = (char *)&pSMBt->hdr.Protocol + data_area_of_target = (char *)&pSMBt->hdr.Protocol +
le16_to_cpu(pSMBt->t2_rsp.DataOffset); get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
/* validate target area */ /* validate target area */
data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
le16_to_cpu(pSMB2->t2_rsp.DataOffset); get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
data_area_of_target += total_in_buf; data_area_of_target += total_in_buf;
/* copy second buffer into end of first buffer */ /* copy second buffer into end of first buffer */
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
total_in_buf += total_in_buf2; total_in_buf += total_in_buf2;
pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); byte_count = get_bcc_le(pTargetSMB);
byte_count += total_in_buf2; byte_count += total_in_buf2;
BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); put_bcc_le(byte_count, pTargetSMB);
byte_count = pTargetSMB->smb_buf_length; byte_count = pTargetSMB->smb_buf_length;
byte_count += total_in_buf2; byte_count += total_in_buf2;
...@@ -334,7 +330,6 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -334,7 +330,6 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
return 0; /* we are done */ return 0; /* we are done */
} else /* more responses to go */ } else /* more responses to go */
return 1; return 1;
} }
static void static void
...@@ -2937,8 +2932,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2937,8 +2932,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
TCONX_RSP *pSMBr; TCONX_RSP *pSMBr;
unsigned char *bcc_ptr; unsigned char *bcc_ptr;
int rc = 0; int rc = 0;
int length, bytes_left; int length;
__u16 count; __u16 bytes_left, count;
if (ses == NULL) if (ses == NULL)
return -EIO; return -EIO;
...@@ -3032,7 +3027,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3032,7 +3027,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
tcon->need_reconnect = false; tcon->need_reconnect = false;
tcon->tid = smb_buffer_response->Tid; tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
bytes_left = BCC(smb_buffer_response); bytes_left = get_bcc(smb_buffer_response);
length = strnlen(bcc_ptr, bytes_left - 2); length = strnlen(bcc_ptr, bytes_left - 2);
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
is_unicode = true; is_unicode = true;
......
...@@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
struct inode *inode = cifs_file->dentry->d_inode; struct inode *inode = cifs_file->dentry->d_inode;
struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
...@@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
if (list_empty(&cifsi->openFileList)) { if (list_empty(&cifsi->openFileList)) {
cFYI(1, "closing last open instance for inode %p", cFYI(1, "closing last open instance for inode %p",
cifs_file->dentry->d_inode); cifs_file->dentry->d_inode);
/* in strict cache mode we need invalidate mapping on the last
close because it may cause a error when we open this file
again and get at least level II oplock */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
CIFS_I(inode)->invalid_mapping = true;
cifs_set_oplock_level(cifsi, 0); cifs_set_oplock_level(cifsi, 0);
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
...@@ -1520,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, ...@@ -1520,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
return rc; return rc;
} }
int cifs_fsync(struct file *file, int datasync) int cifs_strict_fsync(struct file *file, int datasync)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct cifsFileInfo *smbfile = file->private_data; struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid(); xid = GetXid();
cFYI(1, "Sync file - name: %s datasync: 0x%x", cFYI(1, "Sync file - name: %s datasync: 0x%x",
file->f_path.dentry->d_name.name, datasync); file->f_path.dentry->d_name.name, datasync);
rc = filemap_write_and_wait(inode->i_mapping); if (!CIFS_I(inode)->clientCanCacheRead)
if (rc == 0) { cifs_invalidate_mapping(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
tcon = tlink_tcon(smbfile->tlink);
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
FreeXid(xid);
return rc;
}
int cifs_fsync(struct file *file, int datasync)
{
int xid;
int rc = 0;
struct cifsTconInfo *tcon;
struct cifsFileInfo *smbfile = file->private_data;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
xid = GetXid();
cFYI(1, "Sync file - name: %s datasync: 0x%x",
file->f_path.dentry->d_name.name, datasync);
tcon = tlink_tcon(smbfile->tlink); tcon = tlink_tcon(smbfile->tlink);
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
}
FreeXid(xid); FreeXid(xid);
return rc; return rc;
...@@ -1591,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id) ...@@ -1591,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id)
return rc; return rc;
} }
ssize_t cifs_user_read(struct file *file, char __user *read_data, static ssize_t
size_t read_size, loff_t *poffset) cifs_iovec_read(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *poffset)
{ {
int rc = -EACCES; int rc;
unsigned int bytes_read = 0; int xid;
unsigned int total_read = 0; unsigned int total_read, bytes_read = 0;
unsigned int current_read_size; size_t len, cur_len;
int iov_offset = 0;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int xid;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
char *smb_read_data;
char __user *current_offset;
struct smb_com_read_rsp *pSMBr; struct smb_com_read_rsp *pSMBr;
char *read_data;
if (!nr_segs)
return 0;
len = iov_length(iov, nr_segs);
if (!len)
return 0;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (file->private_data == NULL) {
rc = -EBADF;
FreeXid(xid);
return rc;
}
open_file = file->private_data; open_file = file->private_data;
pTcon = tlink_tcon(open_file->tlink); pTcon = tlink_tcon(open_file->tlink);
if ((file->f_flags & O_ACCMODE) == O_WRONLY) if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance"); cFYI(1, "attempting read on write only file instance");
for (total_read = 0, current_offset = read_data; for (total_read = 0; total_read < len; total_read += bytes_read) {
read_size > total_read; cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize);
total_read += bytes_read, current_offset += bytes_read) {
current_read_size = min_t(const int, read_size - total_read,
cifs_sb->rsize);
rc = -EAGAIN; rc = -EAGAIN;
smb_read_data = NULL; read_data = NULL;
while (rc == -EAGAIN) { while (rc == -EAGAIN) {
int buf_type = CIFS_NO_BUFFER; int buf_type = CIFS_NO_BUFFER;
if (open_file->invalidHandle) { if (open_file->invalidHandle) {
...@@ -1634,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1634,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
if (rc != 0) if (rc != 0)
break; break;
} }
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon, open_file->netfid,
open_file->netfid, cur_len, *poffset, &bytes_read,
current_read_size, *poffset, &read_data, &buf_type);
&bytes_read, &smb_read_data, pSMBr = (struct smb_com_read_rsp *)read_data;
&buf_type); if (read_data) {
pSMBr = (struct smb_com_read_rsp *)smb_read_data; char *data_offset = read_data + 4 +
if (smb_read_data) { le16_to_cpu(pSMBr->DataOffset);
if (copy_to_user(current_offset, if (memcpy_toiovecend(iov, data_offset,
smb_read_data + iov_offset, bytes_read))
4 /* RFC1001 length field */ +
le16_to_cpu(pSMBr->DataOffset),
bytes_read))
rc = -EFAULT; rc = -EFAULT;
if (buf_type == CIFS_SMALL_BUFFER) if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data); cifs_small_buf_release(read_data);
else if (buf_type == CIFS_LARGE_BUFFER) else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data); cifs_buf_release(read_data);
smb_read_data = NULL; read_data = NULL;
iov_offset += bytes_read;
} }
} }
if (rc || (bytes_read == 0)) { if (rc || (bytes_read == 0)) {
if (total_read) { if (total_read) {
break; break;
...@@ -1667,10 +1693,54 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1667,10 +1693,54 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
*poffset += bytes_read; *poffset += bytes_read;
} }
} }
FreeXid(xid); FreeXid(xid);
return total_read; return total_read;
} }
ssize_t cifs_user_read(struct file *file, char __user *read_data,
size_t read_size, loff_t *poffset)
{
struct iovec iov;
iov.iov_base = read_data;
iov.iov_len = read_size;
return cifs_iovec_read(file, &iov, 1, poffset);
}
static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
ssize_t read;
read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos);
if (read > 0)
iocb->ki_pos = pos;
return read;
}
ssize_t cifs_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 cifs_user_readv(iocb, iov, nr_segs, pos);
}
static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
loff_t *poffset) loff_t *poffset)
...@@ -1741,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1741,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return total_read; return total_read;
} }
int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
{
int rc, xid;
struct inode *inode = file->f_path.dentry->d_inode;
xid = GetXid();
if (!CIFS_I(inode)->clientCanCacheRead)
cifs_invalidate_mapping(inode);
rc = generic_file_mmap(file, vma);
FreeXid(xid);
return rc;
}
int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{ {
int rc, xid; int rc, xid;
......
...@@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode) ...@@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode)
inode->i_fop = &cifs_file_direct_nobrl_ops; inode->i_fop = &cifs_file_direct_nobrl_ops;
else else
inode->i_fop = &cifs_file_direct_ops; 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) } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops; inode->i_fop = &cifs_file_nobrl_ops;
else { /* not direct, send byte range locks */ else { /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
} }
/* check if server can support readpages */ /* check if server can support readpages */
if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
...@@ -1679,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode) ...@@ -1679,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode)
/* /*
* Zap the cache. Called when invalid_mapping flag is set. * Zap the cache. Called when invalid_mapping flag is set.
*/ */
static void void
cifs_invalidate_mapping(struct inode *inode) cifs_invalidate_mapping(struct inode *inode)
{ {
int rc; int rc;
......
...@@ -637,77 +637,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) ...@@ -637,77 +637,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
return; return;
} }
/* Convert 16 bit Unicode pathname to wire format from string in current code
page. Conversion may involve remapping up the seven characters that are
only legal in POSIX-like OS (if they are present in the string). Path
names are little endian 16 bit Unicode on the wire */
int
cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
const struct nls_table *cp, int mapChars)
{
int i, j, charlen;
int len_remaining = maxlen;
char src_char;
__u16 temp;
if (!mapChars)
return cifs_strtoUCS(target, source, PATH_MAX, cp);
for (i = 0, j = 0; i < maxlen; j++) {
src_char = source[i];
switch (src_char) {
case 0:
target[j] = 0;
goto ctoUCS_out;
case ':':
target[j] = cpu_to_le16(UNI_COLON);
break;
case '*':
target[j] = cpu_to_le16(UNI_ASTERIK);
break;
case '?':
target[j] = cpu_to_le16(UNI_QUESTION);
break;
case '<':
target[j] = cpu_to_le16(UNI_LESSTHAN);
break;
case '>':
target[j] = cpu_to_le16(UNI_GRTRTHAN);
break;
case '|':
target[j] = cpu_to_le16(UNI_PIPE);
break;
/* BB We can not handle remapping slash until
all the calls to build_path_from_dentry
are modified, as they use slash as separator BB */
/* case '\\':
target[j] = cpu_to_le16(UNI_SLASH);
break;*/
default:
charlen = cp->char2uni(source+i,
len_remaining, &temp);
/* if no match, use question mark, which
at least in some cases servers as wild card */
if (charlen < 1) {
target[j] = cpu_to_le16(0x003f);
charlen = 1;
} else
target[j] = cpu_to_le16(temp);
len_remaining -= charlen;
/* character may take more than one byte in the
the source string, but will take exactly two
bytes in the target string */
i += charlen;
continue;
}
i++; /* move to next char in source string */
len_remaining--;
}
ctoUCS_out:
return i;
}
void void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{ {
......
...@@ -916,14 +916,14 @@ unsigned int ...@@ -916,14 +916,14 @@ unsigned int
smbCalcSize(struct smb_hdr *ptr) smbCalcSize(struct smb_hdr *ptr)
{ {
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + BCC(ptr)); 2 /* size of the bcc field */ + get_bcc(ptr));
} }
unsigned int unsigned int
smbCalcSize_LE(struct smb_hdr *ptr) smbCalcSize_LE(struct smb_hdr *ptr)
{ {
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); 2 /* size of the bcc field */ + get_bcc_le(ptr));
} }
/* The following are taken from fs/ntfs/util.c */ /* The following are taken from fs/ntfs/util.c */
......
...@@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, ...@@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
} }
static void static void
decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
int len; int len;
...@@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, ...@@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
return; return;
} }
static int decode_ascii_ssetup(char **pbcc_area, int bleft, static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
struct cifsSesInfo *ses, struct cifsSesInfo *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
...@@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
char *str_area; char *str_area;
SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMB;
__u32 capabilities; __u32 capabilities;
int count; __u16 count;
int resp_buf_type; int resp_buf_type;
struct kvec iov[3]; struct kvec iov[3];
enum securityEnum type; enum securityEnum type;
__u16 action; __u16 action, bytes_remaining;
int bytes_remaining;
struct key *spnego_key = NULL; struct key *spnego_key = NULL;
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
u16 blob_len; u16 blob_len;
...@@ -876,7 +875,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -876,7 +875,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
count = iov[1].iov_len + iov[2].iov_len; count = iov[1].iov_len + iov[2].iov_len;
smb_buf->smb_buf_length += count; smb_buf->smb_buf_length += count;
BCC_LE(smb_buf) = cpu_to_le16(count); put_bcc_le(count, smb_buf);
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
CIFS_LOG_ERROR); CIFS_LOG_ERROR);
...@@ -910,7 +909,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -910,7 +909,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
cFYI(1, "UID = %d ", ses->Suid); cFYI(1, "UID = %d ", ses->Suid);
/* response can have either 3 or 4 word count - Samba sends 3 */ /* response can have either 3 or 4 word count - Samba sends 3 */
/* and lanman response is 3 */ /* and lanman response is 3 */
bytes_remaining = BCC(smb_buf); bytes_remaining = get_bcc(smb_buf);
bcc_ptr = pByteArea(smb_buf); bcc_ptr = pByteArea(smb_buf);
if (smb_buf->WordCount == 4) { if (smb_buf->WordCount == 4) {
......
...@@ -484,7 +484,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, ...@@ -484,7 +484,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2;
in_buf->Command = SMB_COM_NT_CANCEL; in_buf->Command = SMB_COM_NT_CANCEL;
in_buf->WordCount = 0; in_buf->WordCount = 0;
BCC_LE(in_buf) = 0; put_bcc_le(0, in_buf);
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
...@@ -632,8 +632,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -632,8 +632,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
if (receive_len >= sizeof(struct smb_hdr) - 4 if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ + /* do not count RFC1001 header */ +
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
BCC(midQ->resp_buf) = put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
le16_to_cpu(BCC_LE(midQ->resp_buf));
if ((flags & CIFS_NO_RESP) == 0) if ((flags & CIFS_NO_RESP) == 0)
midQ->resp_buf = NULL; /* mark it so buf will midQ->resp_buf = NULL; /* mark it so buf will
not be freed by not be freed by
...@@ -776,7 +775,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -776,7 +775,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (receive_len >= sizeof(struct smb_hdr) - 4 if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ + /* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ ) (2 * out_buf->WordCount) + 2 /* bcc */ )
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
} else { } else {
rc = -EIO; rc = -EIO;
cERROR(1, "Bad MID state?"); cERROR(1, "Bad MID state?");
...@@ -977,7 +976,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -977,7 +976,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
if (receive_len >= sizeof(struct smb_hdr) - 4 if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ + /* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ ) (2 * out_buf->WordCount) + 2 /* bcc */ )
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); put_bcc(get_bcc_le(out_buf), out_buf);
out: out:
delete_mid(midQ); delete_mid(midQ);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment