Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Linus Torvalds committed Jan 21, 2011
2 parents ebe0d80 + 99d86c8 commit 9093ba5
Show file tree
Hide file tree
Showing 14 changed files with 405 additions and 240 deletions.
1 change: 1 addition & 0 deletions fs/cifs/cifs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
127 changes: 104 additions & 23 deletions fs/cifs/cifs_unicode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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?
*
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

38 changes: 38 additions & 0 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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,
Expand All @@ -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 */
Expand Down
13 changes: 10 additions & 3 deletions fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);

Expand All @@ -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);
Expand Down
36 changes: 14 additions & 22 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,32 +161,24 @@ 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;
struct sockaddr_storage srcaddr; /* locally bind to this IP */
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 */
Expand All @@ -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 */
Expand All @@ -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
};

/*
Expand Down Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 9093ba5

Please sign in to comment.