Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9093ba53 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+104 −23
Original line number Diff line number Diff line
@@ -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;
}
+38 −0
Original line number Diff line number Diff line
@@ -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 */
+10 −3
Original line number Diff line number Diff line
@@ -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);
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);
+14 −22
Original line number Diff line number Diff line
@@ -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 */
Loading