Commit d1bba17e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.8-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:
 "Nine cifs/smb client fixes

   - Four network error fixes (three relating to replays of requests
     that need to be retried, and one fixing some places where we were
     returning the wrong rc up the stack on network errors)

   - Two multichannel fixes including locking fix and case where subset
     of channels need reconnect

   - netfs integration fixup: share remote i_size with netfslib

   - Two small cleanups (one for addressing a clang warning)"

* tag '6.8-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: fix stray unlock in cifs_chan_skip_or_disable
  cifs: set replay flag for retries of write command
  cifs: commands that are retried should have replay flag set
  cifs: helper function to check replayable error codes
  cifs: translate network errors on send to -ECONNABORTED
  cifs: cifs_pick_channel should try selecting active channels
  cifs: Share server EOF pos with netfslib
  smb: Work around Clang __bdos() type confusion
  smb: client: delete "true", "false" defines
parents 3a5879d4 993d1c34
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	struct cached_fid *cfid;
	struct cached_fids *cfids;
	const char *npath;
	int retries = 0, cur_sleep = 1;

	if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
	    is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0))
		return -EOPNOTSUPP;

	ses = tcon->ses;
	server = cifs_pick_channel(ses);
	cfids = tcon->cfids;

	if (!server->ops->new_lease_key)
		return -EIO;

	if (cifs_sb->root == NULL)
		return -ENOENT;

replay_again:
	/* reinitialize for possible replay */
	flags = 0;
	oplock = SMB2_OPLOCK_LEVEL_II;
	server = cifs_pick_channel(ses);

	if (!server->ops->new_lease_key)
		return -EIO;

	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
	if (!utf16_path)
		return -ENOMEM;
@@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	 */
	cfid->has_lease = true;

	if (retries) {
		smb2_set_replay(server, &rqst[0]);
		smb2_set_replay(server, &rqst[1]);
	}

	rc = compound_send_recv(xid, ses, server,
				flags, 2, rqst,
				resp_buftype, rsp_iov);
@@ -367,6 +378,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
		atomic_inc(&tcon->num_remote_opens);
	}
	kfree(utf16_path);

	if (is_replayable_error(rc) &&
	    smb2_should_replay(tcon, &retries, &cur_sleep))
		goto replay_again;

	return rc;
}

+1 −1
Original line number Diff line number Diff line
@@ -572,7 +572,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
		UniStrupr(user);
	} else {
		memset(user, '\0', 2);
		*(u16 *)user = 0;
	}

	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
+14 −3
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb)
	spin_lock_init(&cifs_inode->writers_lock);
	cifs_inode->writers = 0;
	cifs_inode->netfs.inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
	cifs_inode->server_eof = 0;
	cifs_inode->netfs.remote_i_size = 0;
	cifs_inode->uniqueid = 0;
	cifs_inode->createtime = 0;
	cifs_inode->epoch = 0;
@@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
	struct inode *src_inode = file_inode(src_file);
	struct inode *target_inode = file_inode(dst_file);
	struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode);
	struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode);
	struct cifsFileInfo *smb_file_src;
	struct cifsFileInfo *smb_file_target;
	struct cifs_tcon *src_tcon;
@@ -1428,7 +1429,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
	 * Advance the EOF marker after the flush above to the end of the range
	 * if it's short of that.
	 */
	if (src_cifsi->server_eof < off + len) {
	if (src_cifsi->netfs.remote_i_size < off + len) {
		rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);
		if (rc < 0)
			goto unlock;
@@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
	/* Discard all the folios that overlap the destination region. */
	truncate_inode_pages_range(&target_inode->i_data, fstart, fend);

	fscache_invalidate(cifs_inode_cookie(target_inode), NULL,
			   i_size_read(target_inode), 0);

	rc = file_modified(dst_file);
	if (!rc) {
		rc = target_tcon->ses->server->ops->copychunk_range(xid,
			smb_file_src, smb_file_target, off, len, destoff);
		if (rc > 0 && destoff + rc > i_size_read(target_inode))
		if (rc > 0 && destoff + rc > i_size_read(target_inode)) {
			truncate_setsize(target_inode, destoff + rc);
			netfs_resize_file(&target_cifsi->netfs,
					  i_size_read(target_inode), true);
			fscache_resize_cookie(cifs_inode_cookie(target_inode),
					      i_size_read(target_inode));
		}
		if (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point)
			target_cifsi->netfs.zero_point = destoff + rc;
	}

	file_accessed(src_file);
+13 −1
Original line number Diff line number Diff line
@@ -49,6 +49,11 @@
 */
#define CIFS_DEF_ACTIMEO (1 * HZ)

/*
 * max sleep time before retry to server
 */
#define CIFS_MAX_SLEEP 2000

/*
 * max attribute cache timeout (jiffies) - 2^30
 */
@@ -1501,6 +1506,7 @@ struct cifs_writedata {
	struct smbd_mr			*mr;
#endif
	struct cifs_credits		credits;
	bool				replay;
};

/*
@@ -1561,7 +1567,6 @@ struct cifsInodeInfo {
	spinlock_t writers_lock;
	unsigned int writers;		/* Number of writers on this inode */
	unsigned long time;		/* jiffies of last update of inode */
	u64  server_eof;		/* current file size on server -- protected by i_lock */
	u64  uniqueid;			/* server inode number */
	u64  createtime;		/* creation time on server */
	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for this inode */
@@ -1831,6 +1836,13 @@ static inline bool is_retryable_error(int error)
	return false;
}

static inline bool is_replayable_error(int error)
{
	if (error == -EAGAIN || error == -ECONNABORTED)
		return true;
	return false;
}


/* cifs_get_writable_file() flags */
#define FIND_WR_ANY         0
+5 −4
Original line number Diff line number Diff line
@@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
{
	loff_t end_of_write = offset + bytes_written;

	if (end_of_write > cifsi->server_eof)
		cifsi->server_eof = end_of_write;
	if (end_of_write > cifsi->netfs.remote_i_size)
		netfs_resize_file(&cifsi->netfs, end_of_write, true);
}

static ssize_t
@@ -3247,8 +3247,8 @@ cifs_uncached_writev_complete(struct work_struct *work)

	spin_lock(&inode->i_lock);
	cifs_update_eof(cifsi, wdata->offset, wdata->bytes);
	if (cifsi->server_eof > inode->i_size)
		i_size_write(inode, cifsi->server_eof);
	if (cifsi->netfs.remote_i_size > inode->i_size)
		i_size_write(inode, cifsi->netfs.remote_i_size);
	spin_unlock(&inode->i_lock);

	complete(&wdata->done);
@@ -3300,6 +3300,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
			if (wdata->cfile->invalidHandle)
				rc = -EAGAIN;
			else {
				wdata->replay = true;
#ifdef CONFIG_CIFS_SMB_DIRECT
				if (wdata->mr) {
					wdata->mr->need_invalidate = true;
Loading