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

Commit 84ced7fd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "This is a set of CIFS/SMB3 fixes for stable.

  There is another set of four SMB3 reconnect fixes for stable in
  progress but they are still being reviewed/tested, so didn't want to
  wait any longer to send these five below"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  Reset TreeId to zero on SMB2 TREE_CONNECT
  CIFS: Fix build failure with smb2
  Introduce cifs_copy_file_range()
  SMB3: Rename clone_range to copychunk_range
  Handle mismatched open calls
parents 462e9a35 806a28ef
Loading
Loading
Loading
Loading
+87 −0
Original line number Original line Diff line number Diff line
@@ -972,6 +972,86 @@ static int cifs_clone_file_range(struct file *src_file, loff_t off,
	return rc;
	return rc;
}
}


ssize_t cifs_file_copychunk_range(unsigned int xid,
				struct file *src_file, loff_t off,
				struct file *dst_file, loff_t destoff,
				size_t len, unsigned int flags)
{
	struct inode *src_inode = file_inode(src_file);
	struct inode *target_inode = file_inode(dst_file);
	struct cifsFileInfo *smb_file_src;
	struct cifsFileInfo *smb_file_target;
	struct cifs_tcon *src_tcon;
	struct cifs_tcon *target_tcon;
	ssize_t rc;

	cifs_dbg(FYI, "copychunk range\n");

	if (src_inode == target_inode) {
		rc = -EINVAL;
		goto out;
	}

	if (!src_file->private_data || !dst_file->private_data) {
		rc = -EBADF;
		cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
		goto out;
	}

	rc = -EXDEV;
	smb_file_target = dst_file->private_data;
	smb_file_src = src_file->private_data;
	src_tcon = tlink_tcon(smb_file_src->tlink);
	target_tcon = tlink_tcon(smb_file_target->tlink);

	if (src_tcon->ses != target_tcon->ses) {
		cifs_dbg(VFS, "source and target of copy not on same server\n");
		goto out;
	}

	/*
	 * Note: cifs case is easier than btrfs since server responsible for
	 * checks for proper open modes and file type and if it wants
	 * server could even support copy of range where source = target
	 */
	lock_two_nondirectories(target_inode, src_inode);

	cifs_dbg(FYI, "about to flush pages\n");
	/* should we flush first and last page first */
	truncate_inode_pages(&target_inode->i_data, 0);

	if (target_tcon->ses->server->ops->copychunk_range)
		rc = target_tcon->ses->server->ops->copychunk_range(xid,
			smb_file_src, smb_file_target, off, len, destoff);
	else
		rc = -EOPNOTSUPP;

	/* force revalidate of size and timestamps of target file now
	 * that target is updated on the server
	 */
	CIFS_I(target_inode)->time = 0;
	/* although unlocking in the reverse order from locking is not
	 * strictly necessary here it is a little cleaner to be consistent
	 */
	unlock_two_nondirectories(src_inode, target_inode);

out:
	return rc;
}

static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
				struct file *dst_file, loff_t destoff,
				size_t len, unsigned int flags)
{
	unsigned int xid = get_xid();
	ssize_t rc;

	rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
					len, flags);
	free_xid(xid);
	return rc;
}

const struct file_operations cifs_file_ops = {
const struct file_operations cifs_file_ops = {
	.read_iter = cifs_loose_read_iter,
	.read_iter = cifs_loose_read_iter,
	.write_iter = cifs_file_write_iter,
	.write_iter = cifs_file_write_iter,
@@ -984,6 +1064,7 @@ const struct file_operations cifs_file_ops = {
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.unlocked_ioctl	= cifs_ioctl,
	.unlocked_ioctl	= cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
	.fallocate = cifs_fallocate,
	.fallocate = cifs_fallocate,
@@ -1001,6 +1082,7 @@ const struct file_operations cifs_file_strict_ops = {
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.unlocked_ioctl	= cifs_ioctl,
	.unlocked_ioctl	= cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
	.fallocate = cifs_fallocate,
	.fallocate = cifs_fallocate,
@@ -1018,6 +1100,7 @@ const struct file_operations cifs_file_direct_ops = {
	.mmap = cifs_file_mmap,
	.mmap = cifs_file_mmap,
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.unlocked_ioctl  = cifs_ioctl,
	.unlocked_ioctl  = cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
@@ -1035,6 +1118,7 @@ const struct file_operations cifs_file_nobrl_ops = {
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.unlocked_ioctl	= cifs_ioctl,
	.unlocked_ioctl	= cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
	.fallocate = cifs_fallocate,
	.fallocate = cifs_fallocate,
@@ -1051,6 +1135,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.unlocked_ioctl	= cifs_ioctl,
	.unlocked_ioctl	= cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
	.fallocate = cifs_fallocate,
	.fallocate = cifs_fallocate,
@@ -1067,6 +1152,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
	.mmap = cifs_file_mmap,
	.mmap = cifs_file_mmap,
	.splice_read = generic_file_splice_read,
	.splice_read = generic_file_splice_read,
	.unlocked_ioctl  = cifs_ioctl,
	.unlocked_ioctl  = cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.llseek = cifs_llseek,
	.llseek = cifs_llseek,
	.setlease = cifs_setlease,
	.setlease = cifs_setlease,
@@ -1078,6 +1164,7 @@ const struct file_operations cifs_dir_ops = {
	.release = cifs_closedir,
	.release = cifs_closedir,
	.read    = generic_read_dir,
	.read    = generic_read_dir,
	.unlocked_ioctl  = cifs_ioctl,
	.unlocked_ioctl  = cifs_ioctl,
	.copy_file_range = cifs_copy_file_range,
	.clone_file_range = cifs_clone_file_range,
	.clone_file_range = cifs_clone_file_range,
	.llseek = generic_file_llseek,
	.llseek = generic_file_llseek,
};
};
+5 −0
Original line number Original line Diff line number Diff line
@@ -139,6 +139,11 @@ extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
# define cifs_listxattr NULL
# define cifs_listxattr NULL
#endif
#endif


extern ssize_t cifs_file_copychunk_range(unsigned int xid,
					struct file *src_file, loff_t off,
					struct file *dst_file, loff_t destoff,
					size_t len, unsigned int flags);

extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_CIFS_NFSD_EXPORT
#ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops;
extern const struct export_operations cifs_export_ops;
+15 −3
Original line number Original line Diff line number Diff line
@@ -243,6 +243,7 @@ struct smb_version_operations {
	/* verify the message */
	/* verify the message */
	int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
	int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
	int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *);
	void (*downgrade_oplock)(struct TCP_Server_Info *,
	void (*downgrade_oplock)(struct TCP_Server_Info *,
					struct cifsInodeInfo *, bool);
					struct cifsInodeInfo *, bool);
	/* process transaction2 response */
	/* process transaction2 response */
@@ -407,9 +408,10 @@ struct smb_version_operations {
	char * (*create_lease_buf)(u8 *, u8);
	char * (*create_lease_buf)(u8 *, u8);
	/* parse lease context buffer and return oplock/epoch info */
	/* parse lease context buffer and return oplock/epoch info */
	__u8 (*parse_lease_buf)(void *, unsigned int *);
	__u8 (*parse_lease_buf)(void *, unsigned int *);
	int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file,
	ssize_t (*copychunk_range)(const unsigned int,
			struct cifsFileInfo *target_file, u64 src_off, u64 len,
			struct cifsFileInfo *src_file,
			u64 dest_off);
			struct cifsFileInfo *target_file,
			u64 src_off, u64 len, u64 dest_off);
	int (*duplicate_extents)(const unsigned int, struct cifsFileInfo *src,
	int (*duplicate_extents)(const unsigned int, struct cifsFileInfo *src,
			struct cifsFileInfo *target_file, u64 src_off, u64 len,
			struct cifsFileInfo *target_file, u64 src_off, u64 len,
			u64 dest_off);
			u64 dest_off);
@@ -1343,6 +1345,7 @@ struct mid_q_entry {
	void *callback_data;	  /* general purpose pointer for callback */
	void *callback_data;	  /* general purpose pointer for callback */
	void *resp_buf;		/* pointer to received SMB header */
	void *resp_buf;		/* pointer to received SMB header */
	int mid_state;	/* wish this were enum but can not pass to wait_event */
	int mid_state;	/* wish this were enum but can not pass to wait_event */
	unsigned int mid_flags;
	__le16 command;		/* smb command code */
	__le16 command;		/* smb command code */
	bool large_buf:1;	/* if valid response, is pointer to large buf */
	bool large_buf:1;	/* if valid response, is pointer to large buf */
	bool multiRsp:1;	/* multiple trans2 responses for one request  */
	bool multiRsp:1;	/* multiple trans2 responses for one request  */
@@ -1350,6 +1353,12 @@ struct mid_q_entry {
	bool decrypted:1;	/* decrypted entry */
	bool decrypted:1;	/* decrypted entry */
};
};


struct close_cancelled_open {
	struct cifs_fid         fid;
	struct cifs_tcon        *tcon;
	struct work_struct      work;
};

/*	Make code in transport.c a little cleaner by moving
/*	Make code in transport.c a little cleaner by moving
	update of optional stats into function below */
	update of optional stats into function below */
#ifdef CONFIG_CIFS_STATS2
#ifdef CONFIG_CIFS_STATS2
@@ -1481,6 +1490,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define   MID_RESPONSE_MALFORMED 0x10
#define   MID_RESPONSE_MALFORMED 0x10
#define   MID_SHUTDOWN		 0x20
#define   MID_SHUTDOWN		 0x20


/* Flags */
#define   MID_WAIT_CANCELLED	 1 /* Cancelled while waiting for response */

/* Types of response buffer returned from SendReceive2 */
/* Types of response buffer returned from SendReceive2 */
#define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
#define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
#define   CIFS_SMALL_BUFFER     1
#define   CIFS_SMALL_BUFFER     1
+2 −1
Original line number Original line Diff line number Diff line
@@ -79,7 +79,8 @@ extern void cifs_delete_mid(struct mid_q_entry *mid);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server,
extern int cifs_handle_standard(struct TCP_Server_Info *server,
				struct mid_q_entry *mid);
				struct mid_q_entry *mid);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server,
				       char *buf);
extern int cifs_call_async(struct TCP_Server_Info *server,
extern int cifs_call_async(struct TCP_Server_Info *server,
			struct smb_rqst *rqst,
			struct smb_rqst *rqst,
			mid_receive_t *receive, mid_callback_t *callback,
			mid_receive_t *receive, mid_callback_t *callback,
+7 −4
Original line number Original line Diff line number Diff line
@@ -1400,9 +1400,9 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
 * current bigbuf.
 * current bigbuf.
 */
 */
int
int
cifs_discard_remaining_data(struct TCP_Server_Info *server)
cifs_discard_remaining_data(struct TCP_Server_Info *server, char *buf)
{
{
	unsigned int rfclen = get_rfc1002_length(server->smallbuf);
	unsigned int rfclen = get_rfc1002_length(buf);
	int remaining = rfclen + 4 - server->total_read;
	int remaining = rfclen + 4 - server->total_read;


	while (remaining > 0) {
	while (remaining > 0) {
@@ -1426,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
	int length;
	int length;
	struct cifs_readdata *rdata = mid->callback_data;
	struct cifs_readdata *rdata = mid->callback_data;


	length = cifs_discard_remaining_data(server);
	length = cifs_discard_remaining_data(server, mid->resp_buf);
	dequeue_mid(mid, rdata->result);
	dequeue_mid(mid, rdata->result);
	return length;
	return length;
}
}
@@ -1459,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)


	if (server->ops->is_status_pending &&
	if (server->ops->is_status_pending &&
	    server->ops->is_status_pending(buf, server, 0)) {
	    server->ops->is_status_pending(buf, server, 0)) {
		cifs_discard_remaining_data(server);
		cifs_discard_remaining_data(server, buf);
		return -1;
		return -1;
	}
	}


@@ -1519,6 +1519,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
		 rdata->iov[0].iov_base, server->total_read);
		 rdata->iov[0].iov_base, server->total_read);


	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;

	/* how much data is in the response? */
	/* how much data is in the response? */
	data_len = server->ops->read_data_length(buf);
	data_len = server->ops->read_data_length(buf);
	if (data_offset + data_len > buflen) {
	if (data_offset + data_len > buflen) {
Loading