mirror of https://gitee.com/openkylin/linux.git
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
This commit is contained in:
commit
9093ba53b7
|
@ -40,6 +40,7 @@
|
|||
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
|
||||
#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
|
||||
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
|
||||
#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct rb_root tlink_tree;
|
||||
|
|
|
@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
|
|||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
|
||||
for (i = 0; i < maxwords && from[i]; i++) {
|
||||
charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp,
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
for (i = 0; i < maxwords; i++) {
|
||||
ftmp = get_unaligned_le16(&from[i]);
|
||||
if (ftmp == 0)
|
||||
break;
|
||||
|
||||
charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
else
|
||||
|
@ -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
|
||||
* @src_char - 2 byte little-endian source character
|
||||
* @src_char - 2 byte host-endian source character
|
||||
* @cp - codepage to which character should be converted
|
||||
* @mapchar - should character be mapped according to mapchars mount option?
|
||||
*
|
||||
|
@ -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).
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int len = 1;
|
||||
|
@ -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
|
||||
* separator.
|
||||
*/
|
||||
switch (le16_to_cpu(src_char)) {
|
||||
switch (src_char) {
|
||||
case UNI_COLON:
|
||||
*target = ':';
|
||||
break;
|
||||
|
@ -109,8 +113,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
|
|||
return len;
|
||||
|
||||
cp_convert:
|
||||
len = cp->uni2char(le16_to_cpu(src_char), target,
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
|
||||
if (len <= 0) {
|
||||
*target = '?';
|
||||
len = 1;
|
||||
|
@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
|
|||
int nullsize = nls_nullsize(codepage);
|
||||
int fromwords = fromlen / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
|
||||
/*
|
||||
* 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,
|
|||
*/
|
||||
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
|
||||
* conversion bleed into the null terminator
|
||||
*/
|
||||
if (outlen >= safelen) {
|
||||
charlen = cifs_mapchar(tmp, from[i], codepage, mapchar);
|
||||
charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
|
||||
if ((outlen + charlen) > (tolen - nullsize))
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
|
|||
{
|
||||
int charlen;
|
||||
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) {
|
||||
|
||||
/* works for 2.4.0 kernel or later */
|
||||
charlen = codepage->char2uni(from, len, &wchar_to[i]);
|
||||
charlen = codepage->char2uni(from, len, &wchar_to);
|
||||
if (charlen < 1) {
|
||||
cERROR(1, "strtoUCS: char2uni of %d returned %d",
|
||||
(int)*from, charlen);
|
||||
cERROR(1, "strtoUCS: char2uni of 0x%x returned %d",
|
||||
*from, charlen);
|
||||
/* A question mark */
|
||||
to[i] = cpu_to_le16(0x003f);
|
||||
wchar_to = 0x003f;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
|
|||
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 = {
|
|||
.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 = {
|
||||
/* no aio, no readv -
|
||||
BB reevaluate whether they can be done with directio, no cache */
|
||||
|
@ -751,6 +770,7 @@ const struct file_operations cifs_file_direct_ops = {
|
|||
.llseek = cifs_llseek,
|
||||
.setlease = cifs_setlease,
|
||||
};
|
||||
|
||||
const struct file_operations cifs_file_nobrl_ops = {
|
||||
.read = do_sync_read,
|
||||
.write = do_sync_write,
|
||||
|
@ -769,6 +789,24 @@ const struct file_operations cifs_file_nobrl_ops = {
|
|||
.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 = {
|
||||
/* no mmap, no aio, no readv -
|
||||
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 *,
|
|||
struct dentry *);
|
||||
extern int cifs_revalidate_file(struct file *filp);
|
||||
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_setattr(struct dentry *, struct iattr *);
|
||||
|
||||
|
@ -72,19 +73,25 @@ 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 */
|
||||
extern const struct file_operations cifs_file_nobrl_ops;
|
||||
extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
|
||||
extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
|
||||
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_close(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,
|
||||
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,
|
||||
size_t write_size, loff_t *poffset);
|
||||
extern int cifs_lock(struct file *, int, struct file_lock *);
|
||||
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_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 int cifs_dir_open(struct inode *inode, struct file *file);
|
||||
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
|
||||
|
|
|
@ -161,6 +161,7 @@ struct TCP_Server_Info {
|
|||
int srv_count; /* reference counter */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
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 */
|
||||
struct socket *ssocket;
|
||||
struct sockaddr_storage dstaddr;
|
||||
|
@ -168,25 +169,16 @@ struct TCP_Server_Info {
|
|||
wait_queue_head_t response_q;
|
||||
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
|
||||
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 noautotune; /* do not autotune send buf sizes */
|
||||
bool tcp_nodelay;
|
||||
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 task_struct *tsk;
|
||||
char server_GUID[16];
|
||||
char secMode;
|
||||
bool session_estab; /* mark when very first sess is established */
|
||||
u16 dialect; /* dialect index that server chose */
|
||||
enum securityEnum secType;
|
||||
unsigned int maxReq; /* Clients should submit no more */
|
||||
/* than maxReq distinct unanswered SMBs to the server when using */
|
||||
|
@ -199,8 +191,6 @@ struct TCP_Server_Info {
|
|||
unsigned int max_vcs; /* maximum number of smb sessions, at least
|
||||
those that can be specified uniquely with
|
||||
vcnumbers */
|
||||
char sessid[4]; /* unique token id for this session */
|
||||
/* (returned on Negotiate */
|
||||
int capabilities; /* allow selective disabling of caps by smb sess */
|
||||
int timeAdj; /* Adjust for difference in server time zone in sec */
|
||||
__u16 CurrentMid; /* multiplex id - rotating counter */
|
||||
|
@ -210,18 +200,20 @@ struct TCP_Server_Info {
|
|||
__u32 sequence_number; /* for signing, protected by srv_mutex */
|
||||
struct session_key session_key;
|
||||
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 */
|
||||
/* 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_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 */
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
struct fscache_cookie *fscache; /* client index cache cookie */
|
||||
#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 {
|
|||
/* BB add in lists for dirty pages i.e. write caching info for oplock */
|
||||
struct list_head openFileList;
|
||||
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
|
||||
unsigned long time; /* jiffies of last update/check of inode */
|
||||
bool clientCanCacheRead:1; /* read oplock */
|
||||
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
||||
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
||||
bool invalid_mapping:1; /* pagecache is invalid */
|
||||
bool clientCanCacheRead; /* read oplock */
|
||||
bool clientCanCacheAll; /* read and writebehind oplock */
|
||||
bool delete_pending; /* DELETE_ON_CLOSE is set */
|
||||
bool invalid_mapping; /* pagecache is invalid */
|
||||
unsigned long time; /* jiffies of last update of inode */
|
||||
u64 server_eof; /* current file size on server */
|
||||
u64 uniqueid; /* server inode number */
|
||||
u64 createtime; /* creation time on server */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define _CIFSPDU_H
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "smbfsctl.h"
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
|
@ -426,11 +427,49 @@ struct smb_hdr {
|
|||
__u16 Mid;
|
||||
__u8 WordCount;
|
||||
} __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)))
|
||||
#define BCC_LE(smb_var) (*(__le16 *)((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(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 */
|
||||
#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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
int rc = -EINVAL;
|
||||
int total_size;
|
||||
char *pBCC;
|
||||
unsigned int total_size;
|
||||
|
||||
/* 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 */
|
||||
if (pSMB->hdr.WordCount >= 10) {
|
||||
if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
|
||||
(le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
|
||||
/* check that bcc is at least as big as parms + data */
|
||||
/* check that bcc is less than negotiated smb buffer */
|
||||
total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
|
||||
if (total_size < 512) {
|
||||
total_size +=
|
||||
le16_to_cpu(pSMB->t2_rsp.DataCount);
|
||||
/* BCC le converted in SendReceive */
|
||||
pBCC = (pSMB->hdr.WordCount * 2) +
|
||||
sizeof(struct smb_hdr) +
|
||||
(char *)pSMB;
|
||||
if ((total_size <= (*(u16 *)pBCC)) &&
|
||||
(total_size <
|
||||
CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
|
||||
get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
|
||||
goto vt2_err;
|
||||
|
||||
/* check that bcc is at least as big as parms + data */
|
||||
/* check that bcc is less than negotiated smb buffer */
|
||||
total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
|
||||
if (total_size >= 512)
|
||||
goto vt2_err;
|
||||
|
||||
total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
|
||||
if (total_size > get_bcc(&pSMB->hdr) ||
|
||||
total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
|
||||
goto vt2_err;
|
||||
|
||||
return 0;
|
||||
vt2_err:
|
||||
cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
|
||||
sizeof(struct smb_t2_rsp) + 16);
|
||||
return rc;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
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),
|
||||
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
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
|
||||
accurately, in case we ever find a need for it */
|
||||
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
|
||||
|
@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
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->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
|
||||
server->timeAdj *= 60;
|
||||
|
@ -737,9 +733,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
|
|||
|
||||
/* set up echo request */
|
||||
smb->hdr.Tid = cpu_to_le16(0xffff);
|
||||
smb->hdr.WordCount = cpu_to_le16(1);
|
||||
smb->EchoCount = cpu_to_le16(1);
|
||||
smb->ByteCount = cpu_to_le16(1);
|
||||
smb->hdr.WordCount = 1;
|
||||
put_unaligned_le16(1, &smb->EchoCount);
|
||||
put_bcc_le(1, &smb->hdr);
|
||||
smb->Data[0] = 'a';
|
||||
smb->hdr.smb_buf_length += 3;
|
||||
|
||||
|
@ -5611,7 +5607,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
|||
}
|
||||
|
||||
/* 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) {
|
||||
cFYI(1, "EA list appears to go beyond SMB");
|
||||
rc = -EIO;
|
||||
|
|
|
@ -232,9 +232,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
|
||||
{
|
||||
struct smb_t2_rsp *pSMBt;
|
||||
int total_data_size;
|
||||
int data_in_this_rsp;
|
||||
int remaining;
|
||||
__u16 total_data_size, data_in_this_rsp;
|
||||
|
||||
if (pSMB->Command != SMB_COM_TRANSACTION2)
|
||||
return 0;
|
||||
|
@ -248,8 +247,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
|
|||
|
||||
pSMBt = (struct smb_t2_rsp *)pSMB;
|
||||
|
||||
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
|
||||
data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
|
||||
total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||
data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||
|
||||
remaining = total_data_size - data_in_this_rsp;
|
||||
|
||||
|
@ -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 *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_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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -299,28 +295,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
|
|||
if (remaining == 0) /* nothing to do, ignore */
|
||||
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) {
|
||||
cFYI(1, "transact2 2nd response contains too much data");
|
||||
}
|
||||
|
||||
/* find end of first SMB data area */
|
||||
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 */
|
||||
|
||||
data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
|
||||
le16_to_cpu(pSMB2->t2_rsp.DataOffset);
|
||||
data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
|
||||
get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
|
||||
|
||||
data_area_of_target += total_in_buf;
|
||||
|
||||
/* copy second buffer into end of first buffer */
|
||||
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
|
||||
total_in_buf += total_in_buf2;
|
||||
pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
|
||||
byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
|
||||
put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
|
||||
byte_count = get_bcc_le(pTargetSMB);
|
||||
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 += total_in_buf2;
|
||||
|
@ -334,7 +330,6 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
|
|||
return 0; /* we are done */
|
||||
} else /* more responses to go */
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2937,8 +2932,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
TCONX_RSP *pSMBr;
|
||||
unsigned char *bcc_ptr;
|
||||
int rc = 0;
|
||||
int length, bytes_left;
|
||||
__u16 count;
|
||||
int length;
|
||||
__u16 bytes_left, count;
|
||||
|
||||
if (ses == NULL)
|
||||
return -EIO;
|
||||
|
@ -3032,7 +3027,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
tcon->need_reconnect = false;
|
||||
tcon->tid = smb_buffer_response->Tid;
|
||||
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);
|
||||
if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
|
||||
is_unicode = true;
|
||||
|
|
175
fs/cifs/file.c
175
fs/cifs/file.c
|
@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|||
struct inode *inode = cifs_file->dentry->d_inode;
|
||||
struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifsLockInfo *li, *tmp;
|
||||
|
||||
spin_lock(&cifs_file_list_lock);
|
||||
|
@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|||
if (list_empty(&cifsi->openFileList)) {
|
||||
cFYI(1, "closing last open instance for inode %p",
|
||||
cifs_file->dentry->d_inode);
|
||||
|
||||
/* in strict cache mode we need invalidate mapping on the last
|
||||
close because it may cause a error when we open this file
|
||||
again and get at least level II oplock */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
|
||||
CIFS_I(inode)->invalid_mapping = true;
|
||||
|
||||
cifs_set_oplock_level(cifsi, 0);
|
||||
}
|
||||
spin_unlock(&cifs_file_list_lock);
|
||||
|
@ -1520,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int cifs_fsync(struct file *file, int datasync)
|
||||
int cifs_strict_fsync(struct file *file, int datasync)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0;
|
||||
struct cifsTconInfo *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);
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, "Sync file - name: %s datasync: 0x%x",
|
||||
file->f_path.dentry->d_name.name, datasync);
|
||||
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc == 0) {
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
if (!CIFS_I(inode)->clientCanCacheRead)
|
||||
cifs_invalidate_mapping(inode);
|
||||
|
||||
tcon = tlink_tcon(smbfile->tlink);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
|
||||
rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
|
||||
}
|
||||
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);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
|
||||
rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
|
@ -1591,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id)
|
|||
return rc;
|
||||
}
|
||||
|
||||
ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
||||
size_t read_size, loff_t *poffset)
|
||||
static ssize_t
|
||||
cifs_iovec_read(struct file *file, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t *poffset)
|
||||
{
|
||||
int rc = -EACCES;
|
||||
unsigned int bytes_read = 0;
|
||||
unsigned int total_read = 0;
|
||||
unsigned int current_read_size;
|
||||
int rc;
|
||||
int xid;
|
||||
unsigned int total_read, bytes_read = 0;
|
||||
size_t len, cur_len;
|
||||
int iov_offset = 0;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
int xid;
|
||||
struct cifsFileInfo *open_file;
|
||||
char *smb_read_data;
|
||||
char __user *current_offset;
|
||||
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();
|
||||
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;
|
||||
pTcon = tlink_tcon(open_file->tlink);
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
|
||||
cFYI(1, "attempting read on write only file instance");
|
||||
|
||||
for (total_read = 0, current_offset = read_data;
|
||||
read_size > total_read;
|
||||
total_read += bytes_read, current_offset += bytes_read) {
|
||||
current_read_size = min_t(const int, read_size - total_read,
|
||||
cifs_sb->rsize);
|
||||
for (total_read = 0; total_read < len; total_read += bytes_read) {
|
||||
cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize);
|
||||
rc = -EAGAIN;
|
||||
smb_read_data = NULL;
|
||||
read_data = NULL;
|
||||
|
||||
while (rc == -EAGAIN) {
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
if (open_file->invalidHandle) {
|
||||
|
@ -1634,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
|||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
rc = CIFSSMBRead(xid, pTcon,
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, &smb_read_data,
|
||||
&buf_type);
|
||||
pSMBr = (struct smb_com_read_rsp *)smb_read_data;
|
||||
if (smb_read_data) {
|
||||
if (copy_to_user(current_offset,
|
||||
smb_read_data +
|
||||
4 /* RFC1001 length field */ +
|
||||
le16_to_cpu(pSMBr->DataOffset),
|
||||
bytes_read))
|
||||
rc = CIFSSMBRead(xid, pTcon, open_file->netfid,
|
||||
cur_len, *poffset, &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(smb_read_data);
|
||||
cifs_small_buf_release(read_data);
|
||||
else if (buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(smb_read_data);
|
||||
smb_read_data = NULL;
|
||||
cifs_buf_release(read_data);
|
||||
read_data = NULL;
|
||||
iov_offset += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc || (bytes_read == 0)) {
|
||||
if (total_read) {
|
||||
break;
|
||||
|
@ -1667,13 +1693,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
|||
*poffset += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
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,
|
||||
loff_t *poffset)
|
||||
loff_t *poffset)
|
||||
{
|
||||
int rc = -EACCES;
|
||||
unsigned int bytes_read = 0;
|
||||
|
@ -1741,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|||
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 rc, xid;
|
||||
|
|
|
@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode)
|
|||
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->maxBuf <
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
|
||||
|
@ -1679,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode)
|
|||
/*
|
||||
* Zap the cache. Called when invalid_mapping flag is set.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
cifs_invalidate_mapping(struct inode *inode)
|
||||
{
|
||||
int rc;
|
||||
|
|
|
@ -637,77 +637,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
|
|||
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
|
||||
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
|
|
|
@ -916,14 +916,14 @@ unsigned int
|
|||
smbCalcSize(struct smb_hdr *ptr)
|
||||
{
|
||||
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
|
||||
smbCalcSize_LE(struct smb_hdr *ptr)
|
||||
{
|
||||
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 */
|
||||
|
|
|
@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int len;
|
||||
|
@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
|
|||
return;
|
||||
}
|
||||
|
||||
static int decode_ascii_ssetup(char **pbcc_area, int bleft,
|
||||
static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
|
||||
struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls_cp)
|
||||
{
|
||||
|
@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
char *str_area;
|
||||
SESSION_SETUP_ANDX *pSMB;
|
||||
__u32 capabilities;
|
||||
int count;
|
||||
__u16 count;
|
||||
int resp_buf_type;
|
||||
struct kvec iov[3];
|
||||
enum securityEnum type;
|
||||
__u16 action;
|
||||
int bytes_remaining;
|
||||
__u16 action, bytes_remaining;
|
||||
struct key *spnego_key = NULL;
|
||||
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
|
||||
u16 blob_len;
|
||||
|
@ -876,7 +875,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
count = iov[1].iov_len + iov[2].iov_len;
|
||||
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,
|
||||
CIFS_LOG_ERROR);
|
||||
|
@ -910,7 +909,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
cFYI(1, "UID = %d ", ses->Suid);
|
||||
/* response can have either 3 or 4 word count - Samba sends 3 */
|
||||
/* and lanman response is 3 */
|
||||
bytes_remaining = BCC(smb_buf);
|
||||
bytes_remaining = get_bcc(smb_buf);
|
||||
bcc_ptr = pByteArea(smb_buf);
|
||||
|
||||
if (smb_buf->WordCount == 4) {
|
||||
|
|
|
@ -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->Command = SMB_COM_NT_CANCEL;
|
||||
in_buf->WordCount = 0;
|
||||
BCC_LE(in_buf) = 0;
|
||||
put_bcc_le(0, in_buf);
|
||||
|
||||
mutex_lock(&server->srv_mutex);
|
||||
rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
|
||||
|
@ -632,8 +632,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(midQ->resp_buf) =
|
||||
le16_to_cpu(BCC_LE(midQ->resp_buf));
|
||||
put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL; /* mark it so buf will
|
||||
not be freed by
|
||||
|
@ -776,7 +775,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(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 {
|
||||
rc = -EIO;
|
||||
cERROR(1, "Bad MID state?");
|
||||
|
@ -977,7 +976,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(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:
|
||||
delete_mid(midQ);
|
||||
|
|
Loading…
Reference in New Issue