Commit d1bba17e authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct cached_fid *cfid; struct cached_fid *cfid;
struct cached_fids *cfids; struct cached_fids *cfids;
const char *npath; const char *npath;
int retries = 0, cur_sleep = 1;
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache || if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0)) is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0))
return -EOPNOTSUPP; return -EOPNOTSUPP;
ses = tcon->ses; ses = tcon->ses;
server = cifs_pick_channel(ses);
cfids = tcon->cfids; cfids = tcon->cfids;
if (!server->ops->new_lease_key)
return -EIO;
if (cifs_sb->root == NULL) if (cifs_sb->root == NULL)
return -ENOENT; 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); utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path) if (!utf16_path)
return -ENOMEM; return -ENOMEM;
...@@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
*/ */
cfid->has_lease = true; 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, rc = compound_send_recv(xid, ses, server,
flags, 2, rqst, flags, 2, rqst,
resp_buftype, rsp_iov); resp_buftype, rsp_iov);
...@@ -367,6 +378,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -367,6 +378,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
atomic_inc(&tcon->num_remote_opens); atomic_inc(&tcon->num_remote_opens);
} }
kfree(utf16_path); kfree(utf16_path);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
......
...@@ -572,7 +572,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -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); len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
UniStrupr(user); UniStrupr(user);
} else { } else {
memset(user, '\0', 2); *(u16 *)user = 0;
} }
rc = crypto_shash_update(ses->server->secmech.hmacmd5, rc = crypto_shash_update(ses->server->secmech.hmacmd5,
......
...@@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb)
spin_lock_init(&cifs_inode->writers_lock); spin_lock_init(&cifs_inode->writers_lock);
cifs_inode->writers = 0; cifs_inode->writers = 0;
cifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 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->uniqueid = 0;
cifs_inode->createtime = 0; cifs_inode->createtime = 0;
cifs_inode->epoch = 0; cifs_inode->epoch = 0;
...@@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, ...@@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
struct inode *src_inode = file_inode(src_file); struct inode *src_inode = file_inode(src_file);
struct inode *target_inode = file_inode(dst_file); struct inode *target_inode = file_inode(dst_file);
struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); 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_src;
struct cifsFileInfo *smb_file_target; struct cifsFileInfo *smb_file_target;
struct cifs_tcon *src_tcon; struct cifs_tcon *src_tcon;
...@@ -1428,7 +1429,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, ...@@ -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 * Advance the EOF marker after the flush above to the end of the range
* if it's short of that. * 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); rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);
if (rc < 0) if (rc < 0)
goto unlock; goto unlock;
...@@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, ...@@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
/* Discard all the folios that overlap the destination region. */ /* Discard all the folios that overlap the destination region. */
truncate_inode_pages_range(&target_inode->i_data, fstart, fend); 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); rc = file_modified(dst_file);
if (!rc) { if (!rc) {
rc = target_tcon->ses->server->ops->copychunk_range(xid, rc = target_tcon->ses->server->ops->copychunk_range(xid,
smb_file_src, smb_file_target, off, len, destoff); 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); 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); file_accessed(src_file);
......
...@@ -49,6 +49,11 @@ ...@@ -49,6 +49,11 @@
*/ */
#define CIFS_DEF_ACTIMEO (1 * HZ) #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 * max attribute cache timeout (jiffies) - 2^30
*/ */
...@@ -1501,6 +1506,7 @@ struct cifs_writedata { ...@@ -1501,6 +1506,7 @@ struct cifs_writedata {
struct smbd_mr *mr; struct smbd_mr *mr;
#endif #endif
struct cifs_credits credits; struct cifs_credits credits;
bool replay;
}; };
/* /*
...@@ -1561,7 +1567,6 @@ struct cifsInodeInfo { ...@@ -1561,7 +1567,6 @@ struct cifsInodeInfo {
spinlock_t writers_lock; spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */ unsigned int writers; /* Number of writers on this inode */
unsigned long time; /* jiffies of last update of 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 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */ u64 createtime; /* creation time on server */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */ __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */
...@@ -1831,6 +1836,13 @@ static inline bool is_retryable_error(int error) ...@@ -1831,6 +1836,13 @@ static inline bool is_retryable_error(int error)
return false; return false;
} }
static inline bool is_replayable_error(int error)
{
if (error == -EAGAIN || error == -ECONNABORTED)
return true;
return false;
}
/* cifs_get_writable_file() flags */ /* cifs_get_writable_file() flags */
#define FIND_WR_ANY 0 #define FIND_WR_ANY 0
......
...@@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, ...@@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
{ {
loff_t end_of_write = offset + bytes_written; loff_t end_of_write = offset + bytes_written;
if (end_of_write > cifsi->server_eof) if (end_of_write > cifsi->netfs.remote_i_size)
cifsi->server_eof = end_of_write; netfs_resize_file(&cifsi->netfs, end_of_write, true);
} }
static ssize_t static ssize_t
...@@ -3247,8 +3247,8 @@ cifs_uncached_writev_complete(struct work_struct *work) ...@@ -3247,8 +3247,8 @@ cifs_uncached_writev_complete(struct work_struct *work)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
cifs_update_eof(cifsi, wdata->offset, wdata->bytes); cifs_update_eof(cifsi, wdata->offset, wdata->bytes);
if (cifsi->server_eof > inode->i_size) if (cifsi->netfs.remote_i_size > inode->i_size)
i_size_write(inode, cifsi->server_eof); i_size_write(inode, cifsi->netfs.remote_i_size);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
complete(&wdata->done); complete(&wdata->done);
...@@ -3300,6 +3300,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, ...@@ -3300,6 +3300,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
if (wdata->cfile->invalidHandle) if (wdata->cfile->invalidHandle)
rc = -EAGAIN; rc = -EAGAIN;
else { else {
wdata->replay = true;
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (wdata->mr) { if (wdata->mr) {
wdata->mr->need_invalidate = true; wdata->mr->need_invalidate = true;
......
...@@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) ...@@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
mtime = inode_get_mtime(inode); mtime = inode_get_mtime(inode);
if (timespec64_equal(&mtime, &fattr->cf_mtime) && if (timespec64_equal(&mtime, &fattr->cf_mtime) &&
cifs_i->server_eof == fattr->cf_eof) { cifs_i->netfs.remote_i_size == fattr->cf_eof) {
cifs_dbg(FYI, "%s: inode %llu is unchanged\n", cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
__func__, cifs_i->uniqueid); __func__, cifs_i->uniqueid);
return; return;
...@@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) ...@@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
else else
clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);
cifs_i->server_eof = fattr->cf_eof; cifs_i->netfs.remote_i_size = fattr->cf_eof;
/* /*
* Can't safely change the file size here if the client is writing to * Can't safely change the file size here if the client is writing to
* it due to potential races. * it due to potential races.
...@@ -2858,7 +2858,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2858,7 +2858,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
set_size_out: set_size_out:
if (rc == 0) { if (rc == 0) {
cifsInode->server_eof = attrs->ia_size; netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
cifs_setsize(inode, attrs->ia_size); cifs_setsize(inode, attrs->ia_size);
/* /*
* i_blocks is not related to (i_size / i_blksize), but instead * i_blocks is not related to (i_size / i_blksize), but instead
...@@ -3011,6 +3011,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -3011,6 +3011,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if ((attrs->ia_valid & ATTR_SIZE) && if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) { attrs->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attrs->ia_size); truncate_setsize(inode, attrs->ia_size);
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
} }
...@@ -3210,6 +3211,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -3210,6 +3211,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if ((attrs->ia_valid & ATTR_SIZE) && if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) { attrs->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attrs->ia_size); truncate_setsize(inode, attrs->ia_size);
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
} }
......
...@@ -141,7 +141,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -141,7 +141,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
if (likely(reparse_inode_match(inode, fattr))) { if (likely(reparse_inode_match(inode, fattr))) {
fattr->cf_mode = inode->i_mode; fattr->cf_mode = inode->i_mode;
fattr->cf_rdev = inode->i_rdev; fattr->cf_rdev = inode->i_rdev;
fattr->cf_eof = CIFS_I(inode)->server_eof; fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size;
fattr->cf_symlink_target = NULL; fattr->cf_symlink_target = NULL;
} else { } else {
CIFS_I(inode)->time = 0; CIFS_I(inode)->time = 0;
......
...@@ -120,6 +120,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -120,6 +120,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
unsigned int size[2]; unsigned int size[2];
void *data[2]; void *data[2];
int len; int len;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
oplock = SMB2_OPLOCK_LEVEL_NONE;
num_rqst = 0;
server = cifs_pick_channel(ses);
vars = kzalloc(sizeof(*vars), GFP_ATOMIC); vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
if (vars == NULL) if (vars == NULL)
...@@ -127,8 +135,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -127,8 +135,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
rqst = &vars->rqst[0]; rqst = &vars->rqst[0];
rsp_iov = &vars->rsp_iov[0]; rsp_iov = &vars->rsp_iov[0];
server = cifs_pick_channel(ses);
if (smb3_encryption_required(tcon)) if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
...@@ -463,15 +469,24 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -463,15 +469,24 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
num_rqst++; num_rqst++;
if (cfile) { if (cfile) {
if (retries)
for (i = 1; i < num_rqst - 2; i++)
smb2_set_replay(server, &rqst[i]);
rc = compound_send_recv(xid, ses, server, rc = compound_send_recv(xid, ses, server,
flags, num_rqst - 2, flags, num_rqst - 2,
&rqst[1], &resp_buftype[1], &rqst[1], &resp_buftype[1],
&rsp_iov[1]); &rsp_iov[1]);
} else } else {
if (retries)
for (i = 0; i < num_rqst; i++)
smb2_set_replay(server, &rqst[i]);
rc = compound_send_recv(xid, ses, server, rc = compound_send_recv(xid, ses, server,
flags, num_rqst, flags, num_rqst,
rqst, resp_buftype, rqst, resp_buftype,
rsp_iov); rsp_iov);
}
finished: finished:
num_rqst = 0; num_rqst = 0;
...@@ -620,9 +635,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -620,9 +635,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
} }
SMB2_close_free(&rqst[num_rqst]); SMB2_close_free(&rqst[num_rqst]);
if (cfile)
cifsFileInfo_put(cfile);
num_cmds += 2; num_cmds += 2;
if (out_iov && out_buftype) { if (out_iov && out_buftype) {
memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov)); memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
...@@ -632,7 +644,16 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -632,7 +644,16 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
for (i = 0; i < num_cmds; i++) for (i = 0; i < num_cmds; i++)
free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base); free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
} }
num_cmds -= 2; /* correct num_cmds as there could be a retry */
kfree(vars); kfree(vars);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
if (cfile)
cifsFileInfo_put(cfile);
return rc; return rc;
} }
......
...@@ -1108,7 +1108,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1108,7 +1108,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
{ {
struct smb2_compound_vars *vars; struct smb2_compound_vars *vars;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
struct smb_rqst *rqst; struct smb_rqst *rqst;
struct kvec *rsp_iov; struct kvec *rsp_iov;
__le16 *utf16_path = NULL; __le16 *utf16_path = NULL;
...@@ -1124,6 +1124,13 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1124,6 +1124,13 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_file_full_ea_info *ea = NULL; struct smb2_file_full_ea_info *ea = NULL;
struct smb2_query_info_rsp *rsp; struct smb2_query_info_rsp *rsp;
int rc, used_len = 0; int rc, used_len = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
if (smb3_encryption_required(tcon)) if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
...@@ -1244,6 +1251,12 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1244,6 +1251,12 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
goto sea_exit; goto sea_exit;
smb2_set_related(&rqst[2]); smb2_set_related(&rqst[2]);
if (retries) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
}
rc = compound_send_recv(xid, ses, server, rc = compound_send_recv(xid, ses, server,
flags, 3, rqst, flags, 3, rqst,
resp_buftype, rsp_iov); resp_buftype, rsp_iov);
...@@ -1260,6 +1273,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1260,6 +1273,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
kfree(vars); kfree(vars);
out_free_path: out_free_path:
kfree(utf16_path); kfree(utf16_path);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
#endif #endif
...@@ -1484,7 +1502,7 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1484,7 +1502,7 @@ smb2_ioctl_query_info(const unsigned int xid,
struct smb_rqst *rqst; struct smb_rqst *rqst;
struct kvec *rsp_iov; struct kvec *rsp_iov;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
char __user *arg = (char __user *)p; char __user *arg = (char __user *)p;
struct smb_query_info qi; struct smb_query_info qi;
struct smb_query_info __user *pqi; struct smb_query_info __user *pqi;
...@@ -1501,6 +1519,13 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1501,6 +1519,13 @@ smb2_ioctl_query_info(const unsigned int xid,
void *data[2]; void *data[2];
int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
void (*free_req1_func)(struct smb_rqst *r); void (*free_req1_func)(struct smb_rqst *r);
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
vars = kzalloc(sizeof(*vars), GFP_ATOMIC); vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
if (vars == NULL) if (vars == NULL)
...@@ -1641,6 +1666,12 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1641,6 +1666,12 @@ smb2_ioctl_query_info(const unsigned int xid,
goto free_req_1; goto free_req_1;
smb2_set_related(&rqst[2]); smb2_set_related(&rqst[2]);
if (retries) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
}
rc = compound_send_recv(xid, ses, server, rc = compound_send_recv(xid, ses, server,
flags, 3, rqst, flags, 3, rqst,
resp_buftype, rsp_iov); resp_buftype, rsp_iov);
...@@ -1701,6 +1732,11 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1701,6 +1732,11 @@ smb2_ioctl_query_info(const unsigned int xid,
kfree(buffer); kfree(buffer);
free_vars: free_vars:
kfree(vars); kfree(vars);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -2227,8 +2263,14 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2227,8 +2263,14 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
struct smb2_query_directory_rsp *qd_rsp = NULL; struct smb2_query_directory_rsp *qd_rsp = NULL;
struct smb2_create_rsp *op_rsp = NULL; struct smb2_create_rsp *op_rsp = NULL;
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); struct TCP_Server_Info *server;
int retry_count = 0; int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(tcon->ses);
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path) if (!utf16_path)
...@@ -2278,14 +2320,15 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2278,14 +2320,15 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[1]); smb2_set_related(&rqst[1]);
again: if (retries) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
}
rc = compound_send_recv(xid, tcon->ses, server, rc = compound_send_recv(xid, tcon->ses, server,
flags, 2, rqst, flags, 2, rqst,
resp_buftype, rsp_iov); resp_buftype, rsp_iov);
if (rc == -EAGAIN && retry_count++ < 10)
goto again;
/* If the open failed there is nothing to do */ /* If the open failed there is nothing to do */
op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
if (op_rsp == NULL || op_rsp->hdr.Status != STATUS_SUCCESS) { if (op_rsp == NULL || op_rsp->hdr.Status != STATUS_SUCCESS) {
...@@ -2333,6 +2376,11 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2333,6 +2376,11 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
SMB2_query_directory_free(&rqst[1]); SMB2_query_directory_free(&rqst[1]);
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -2457,6 +2505,22 @@ smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, ...@@ -2457,6 +2505,22 @@ smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
CIFS_CACHE_READ(cinode) ? 1 : 0); CIFS_CACHE_READ(cinode) ? 1 : 0);
} }
void
smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
struct smb2_hdr *shdr;
if (server->dialect < SMB30_PROT_ID)
return;
shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
if (shdr == NULL) {
cifs_dbg(FYI, "shdr NULL in smb2_set_related\n");
return;
}
shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
}
void void
smb2_set_related(struct smb_rqst *rqst) smb2_set_related(struct smb_rqst *rqst)
{ {
...@@ -2529,6 +2593,27 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) ...@@ -2529,6 +2593,27 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
shdr->NextCommand = cpu_to_le32(len); shdr->NextCommand = cpu_to_le32(len);
} }
/*
* helper function for exponential backoff and check if replayable
*/
bool smb2_should_replay(struct cifs_tcon *tcon,
int *pretries,
int *pcur_sleep)
{
if (!pretries || !pcur_sleep)
return false;
if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
msleep(*pcur_sleep);
(*pcur_sleep) = ((*pcur_sleep) << 1);
if ((*pcur_sleep) > CIFS_MAX_SLEEP)
(*pcur_sleep) = CIFS_MAX_SLEEP;
return true;
}
return false;
}
/* /*
* Passes the query info response back to the caller on success. * Passes the query info response back to the caller on success.
* Caller need to free this with free_rsp_buf(). * Caller need to free this with free_rsp_buf().
...@@ -2542,7 +2627,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2542,7 +2627,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
{ {
struct smb2_compound_vars *vars; struct smb2_compound_vars *vars;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int flags = CIFS_CP_CREATE_CLOSE_OP; int flags = CIFS_CP_CREATE_CLOSE_OP;
struct smb_rqst *rqst; struct smb_rqst *rqst;
int resp_buftype[3]; int resp_buftype[3];
...@@ -2553,6 +2638,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2553,6 +2638,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
int rc; int rc;
__le16 *utf16_path; __le16 *utf16_path;
struct cached_fid *cfid = NULL; struct cached_fid *cfid = NULL;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
if (!path) if (!path)
path = ""; path = "";
...@@ -2633,6 +2725,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2633,6 +2725,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
goto qic_exit; goto qic_exit;
smb2_set_related(&rqst[2]); smb2_set_related(&rqst[2]);
if (retries) {
if (!cfid) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[2]);
}
smb2_set_replay(server, &rqst[1]);
}
if (cfid) { if (cfid) {
rc = compound_send_recv(xid, ses, server, rc = compound_send_recv(xid, ses, server,
flags, 1, &rqst[1], flags, 1, &rqst[1],
...@@ -2665,6 +2765,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2665,6 +2765,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
kfree(vars); kfree(vars);
out_free_path: out_free_path:
kfree(utf16_path); kfree(utf16_path);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3213,6 +3318,9 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3213,6 +3318,9 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
cfile->fid.volatile_fid, cfile->pid, new_size); cfile->fid.volatile_fid, cfile->pid, new_size);
if (rc >= 0) { if (rc >= 0) {
truncate_setsize(inode, new_size); truncate_setsize(inode, new_size);
netfs_resize_file(&cifsi->netfs, new_size, true);
if (offset < cifsi->netfs.zero_point)
cifsi->netfs.zero_point = offset;
fscache_resize_cookie(cifs_inode_cookie(inode), new_size); fscache_resize_cookie(cifs_inode_cookie(inode), new_size);
} }
} }
...@@ -3436,7 +3544,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, ...@@ -3436,7 +3544,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, cfile->pid, new_eof); cfile->fid.volatile_fid, cfile->pid, new_eof);
if (rc == 0) { if (rc == 0) {
cifsi->server_eof = new_eof; netfs_resize_file(&cifsi->netfs, new_eof, true);
cifs_setsize(inode, new_eof); cifs_setsize(inode, new_eof);
cifs_truncate_page(inode->i_mapping, inode->i_size); cifs_truncate_page(inode->i_mapping, inode->i_size);
truncate_setsize(inode, new_eof); truncate_setsize(inode, new_eof);
...@@ -3528,8 +3636,9 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3528,8 +3636,9 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
int rc; int rc;
unsigned int xid; unsigned int xid;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct cifsFileInfo *cfile = file->private_data;
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifsFileInfo *cfile = file->private_data;
struct netfs_inode *ictx = &cifsi->netfs;
loff_t old_eof, new_eof; loff_t old_eof, new_eof;
xid = get_xid(); xid = get_xid();
...@@ -3549,6 +3658,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3549,6 +3658,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
goto out_2; goto out_2;
truncate_pagecache_range(inode, off, old_eof); truncate_pagecache_range(inode, off, old_eof);
ictx->zero_point = old_eof;
rc = smb2_copychunk_range(xid, cfile, cfile, off + len, rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
old_eof - off - len, off); old_eof - off - len, off);
...@@ -3563,9 +3673,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3563,9 +3673,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
rc = 0; rc = 0;
cifsi->server_eof = i_size_read(inode) - len; truncate_setsize(inode, new_eof);
truncate_setsize(inode, cifsi->server_eof); netfs_resize_file(&cifsi->netfs, new_eof, true);
fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof); ictx->zero_point = new_eof;
fscache_resize_cookie(cifs_inode_cookie(inode), new_eof);
out_2: out_2:
filemap_invalidate_unlock(inode->i_mapping); filemap_invalidate_unlock(inode->i_mapping);
out: out:
...@@ -3581,6 +3692,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3581,6 +3692,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
unsigned int xid; unsigned int xid;
struct cifsFileInfo *cfile = file->private_data; struct cifsFileInfo *cfile = file->private_data;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct cifsInodeInfo *cifsi = CIFS_I(inode);
__u64 count, old_eof, new_eof; __u64 count, old_eof, new_eof;
xid = get_xid(); xid = get_xid();
...@@ -3608,6 +3720,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, ...@@ -3608,6 +3720,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
goto out_2; goto out_2;
truncate_setsize(inode, new_eof); truncate_setsize(inode, new_eof);
netfs_resize_file(&cifsi->netfs, i_size_read(inode), true);
fscache_resize_cookie(cifs_inode_cookie(inode), i_size_read(inode)); fscache_resize_cookie(cifs_inode_cookie(inode), i_size_read(inode));
rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len); rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
......
...@@ -195,7 +195,6 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses, ...@@ -195,7 +195,6 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses,
pserver = server->primary_server; pserver = server->primary_server;
cifs_signal_cifsd_for_reconnect(pserver, false); cifs_signal_cifsd_for_reconnect(pserver, false);
skip_terminate: skip_terminate:
mutex_unlock(&ses->session_mutex);
return -EHOSTDOWN; return -EHOSTDOWN;
} }
...@@ -2765,7 +2764,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, ...@@ -2765,7 +2764,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
int flags = 0; int flags = 0;
unsigned int total_len; unsigned int total_len;
__le16 *utf16_path = NULL; __le16 *utf16_path = NULL;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
n_iov = 2;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "mkdir\n"); cifs_dbg(FYI, "mkdir\n");
...@@ -2869,6 +2875,10 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, ...@@ -2869,6 +2875,10 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
/* no need to inc num_remote_opens because we close it just below */ /* no need to inc num_remote_opens because we close it just below */
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE, trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES); FILE_WRITE_ATTRIBUTES);
if (retries)
smb2_set_replay(server, &rqst);
/* resource #4: response buffer */ /* resource #4: response buffer */
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
...@@ -2906,6 +2916,11 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, ...@@ -2906,6 +2916,11 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
cifs_small_buf_release(req); cifs_small_buf_release(req);
err_free_path: err_free_path:
kfree(utf16_path); kfree(utf16_path);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3101,12 +3116,18 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -3101,12 +3116,18 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
struct smb2_create_rsp *rsp = NULL; struct smb2_create_rsp *rsp = NULL;
struct cifs_tcon *tcon = oparms->tcon; struct cifs_tcon *tcon = oparms->tcon;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
struct kvec iov[SMB2_CREATE_IOV_SIZE]; struct kvec iov[SMB2_CREATE_IOV_SIZE];
struct kvec rsp_iov = {NULL, 0}; struct kvec rsp_iov = {NULL, 0};
int resp_buftype = CIFS_NO_BUFFER; int resp_buftype = CIFS_NO_BUFFER;
int rc = 0; int rc = 0;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "create/open\n"); cifs_dbg(FYI, "create/open\n");
if (!ses || !server) if (!ses || !server)
...@@ -3128,6 +3149,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -3128,6 +3149,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path, trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
oparms->create_options, oparms->desired_access); oparms->create_options, oparms->desired_access);
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
...@@ -3181,6 +3205,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -3181,6 +3205,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
creat_exit: creat_exit:
SMB2_open_free(&rqst); SMB2_open_free(&rqst);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3305,15 +3334,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -3305,15 +3334,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
int resp_buftype = CIFS_NO_BUFFER; int resp_buftype = CIFS_NO_BUFFER;
int rc = 0; int rc = 0;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
cifs_dbg(FYI, "SMB2 IOCTL\n");
if (out_data != NULL)
*out_data = NULL;
/* zero out returned data len, in case of error */
if (plen)
*plen = 0;
if (!tcon) if (!tcon)
return -EIO; return -EIO;
...@@ -3322,10 +3343,23 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -3322,10 +3343,23 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (!ses) if (!ses)
return -EIO; return -EIO;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses); server = cifs_pick_channel(ses);
if (!server) if (!server)
return -EIO; return -EIO;
cifs_dbg(FYI, "SMB2 IOCTL\n");
if (out_data != NULL)
*out_data = NULL;
/* zero out returned data len, in case of error */
if (plen)
*plen = 0;
if (smb3_encryption_required(tcon)) if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_TRANSFORM_REQ;
...@@ -3340,6 +3374,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -3340,6 +3374,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (rc) if (rc)
goto ioctl_exit; goto ioctl_exit;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
...@@ -3409,6 +3446,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -3409,6 +3446,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
ioctl_exit: ioctl_exit:
SMB2_ioctl_free(&rqst); SMB2_ioctl_free(&rqst);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3480,13 +3522,20 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3480,13 +3522,20 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
struct smb_rqst rqst; struct smb_rqst rqst;
struct smb2_close_rsp *rsp = NULL; struct smb2_close_rsp *rsp = NULL;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
struct kvec iov[1]; struct kvec iov[1];
struct kvec rsp_iov; struct kvec rsp_iov;
int resp_buftype = CIFS_NO_BUFFER; int resp_buftype = CIFS_NO_BUFFER;
int rc = 0; int rc = 0;
int flags = 0; int flags = 0;
bool query_attrs = false; bool query_attrs = false;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
query_attrs = false;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "Close\n"); cifs_dbg(FYI, "Close\n");
...@@ -3512,6 +3561,9 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3512,6 +3561,9 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) if (rc)
goto close_exit; goto close_exit;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
...@@ -3545,6 +3597,11 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3545,6 +3597,11 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n", cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n",
persistent_fid, tmp_rc); persistent_fid, tmp_rc);
} }
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3675,12 +3732,19 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3675,12 +3732,19 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
int flags = 0; int flags = 0;
bool allocated = false; bool allocated = false;
int retries = 0, cur_sleep = 1;
cifs_dbg(FYI, "Query Info\n"); cifs_dbg(FYI, "Query Info\n");
if (!ses) if (!ses)
return -EIO; return -EIO;
replay_again:
/* reinitialize for possible replay */
flags = 0;
allocated = false;
server = cifs_pick_channel(ses); server = cifs_pick_channel(ses);
if (!server) if (!server)
return -EIO; return -EIO;
...@@ -3702,6 +3766,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3702,6 +3766,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
ses->Suid, info_class, (__u32)info_type); ses->Suid, info_class, (__u32)info_type);
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
...@@ -3744,6 +3811,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3744,6 +3811,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
qinf_exit: qinf_exit:
SMB2_query_info_free(&rqst); SMB2_query_info_free(&rqst);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -3844,7 +3916,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3844,7 +3916,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
u32 *plen /* returned data len */) u32 *plen /* returned data len */)
{ {
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
struct smb_rqst rqst; struct smb_rqst rqst;
struct smb2_change_notify_rsp *smb_rsp; struct smb2_change_notify_rsp *smb_rsp;
struct kvec iov[1]; struct kvec iov[1];
...@@ -3852,6 +3924,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3852,6 +3924,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buftype = CIFS_NO_BUFFER; int resp_buftype = CIFS_NO_BUFFER;
int flags = 0; int flags = 0;
int rc = 0; int rc = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "change notify\n"); cifs_dbg(FYI, "change notify\n");
if (!ses || !server) if (!ses || !server)
...@@ -3876,6 +3954,10 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3876,6 +3954,10 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid, trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter); (u8)watch_tree, completion_filter);
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
...@@ -3910,6 +3992,11 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3910,6 +3992,11 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
if (rqst.rq_iov) if (rqst.rq_iov)
cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */ cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */
free_rsp_buf(resp_buftype, rsp_iov.iov_base); free_rsp_buf(resp_buftype, rsp_iov.iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -4152,10 +4239,16 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -4152,10 +4239,16 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
struct smb_rqst rqst; struct smb_rqst rqst;
struct kvec iov[1]; struct kvec iov[1];
struct kvec rsp_iov = {NULL, 0}; struct kvec rsp_iov = {NULL, 0};
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int resp_buftype = CIFS_NO_BUFFER; int resp_buftype = CIFS_NO_BUFFER;
int flags = 0; int flags = 0;
int rc = 0; int rc = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "flush\n"); cifs_dbg(FYI, "flush\n");
if (!ses || !(ses->server)) if (!ses || !(ses->server))
...@@ -4175,6 +4268,10 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -4175,6 +4268,10 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
goto flush_exit; goto flush_exit;
trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid); trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
...@@ -4189,6 +4286,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -4189,6 +4286,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
flush_exit: flush_exit:
SMB2_flush_free(&rqst); SMB2_flush_free(&rqst);
free_rsp_buf(resp_buftype, rsp_iov.iov_base); free_rsp_buf(resp_buftype, rsp_iov.iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -4668,7 +4770,7 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -4668,7 +4770,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
struct cifs_io_parms *io_parms = NULL; struct cifs_io_parms *io_parms = NULL;
int credit_request; int credit_request;
if (!wdata->server) if (!wdata->server || wdata->replay)
server = wdata->server = cifs_pick_channel(tcon->ses); server = wdata->server = cifs_pick_channel(tcon->ses);
/* /*
...@@ -4753,6 +4855,8 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -4753,6 +4855,8 @@ smb2_async_writev(struct cifs_writedata *wdata,
rqst.rq_nvec = 1; rqst.rq_nvec = 1;
rqst.rq_iter = wdata->iter; rqst.rq_iter = wdata->iter;
rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter); rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter);
if (wdata->replay)
smb2_set_replay(server, &rqst);
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (wdata->mr) if (wdata->mr)
iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1); iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
...@@ -4826,18 +4930,21 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -4826,18 +4930,21 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
int flags = 0; int flags = 0;
unsigned int total_len; unsigned int total_len;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
*nbytes = 0; *nbytes = 0;
if (n_vec < 1)
return rc;
if (!io_parms->server) if (!io_parms->server)
io_parms->server = cifs_pick_channel(io_parms->tcon->ses); io_parms->server = cifs_pick_channel(io_parms->tcon->ses);
server = io_parms->server; server = io_parms->server;
if (server == NULL) if (server == NULL)
return -ECONNABORTED; return -ECONNABORTED;
if (n_vec < 1)
return rc;
rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server, rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server,
(void **) &req, &total_len); (void **) &req, &total_len);
if (rc) if (rc)
...@@ -4871,6 +4978,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -4871,6 +4978,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = n_vec + 1; rqst.rq_nvec = n_vec + 1;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, io_parms->tcon->ses, server, rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
&rqst, &rqst,
&resp_buftype, flags, &rsp_iov); &resp_buftype, flags, &rsp_iov);
...@@ -4895,6 +5005,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -4895,6 +5005,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
cifs_small_buf_release(req); cifs_small_buf_release(req);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
if (is_replayable_error(rc) &&
smb2_should_replay(io_parms->tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5206,8 +5321,14 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5206,8 +5321,14 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
struct kvec rsp_iov; struct kvec rsp_iov;
int rc = 0; int rc = 0;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
if (!ses || !(ses->server)) if (!ses || !(ses->server))
return -EIO; return -EIO;
...@@ -5227,6 +5348,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5227,6 +5348,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) if (rc)
goto qdir_exit; goto qdir_exit;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
...@@ -5261,6 +5385,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5261,6 +5385,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
qdir_exit: qdir_exit:
SMB2_query_directory_free(&rqst); SMB2_query_directory_free(&rqst);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5327,8 +5456,14 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5327,8 +5456,14 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0; int rc = 0;
int resp_buftype; int resp_buftype;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
if (!ses || !server) if (!ses || !server)
return -EIO; return -EIO;
...@@ -5356,6 +5491,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5356,6 +5491,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rqst, &resp_buftype, flags,
...@@ -5371,6 +5508,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5371,6 +5508,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
kfree(iov); kfree(iov);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5423,12 +5565,18 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5423,12 +5565,18 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
int rc; int rc;
struct smb2_oplock_break *req = NULL; struct smb2_oplock_break *req = NULL;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
int flags = CIFS_OBREAK_OP; int flags = CIFS_OBREAK_OP;
unsigned int total_len; unsigned int total_len;
struct kvec iov[1]; struct kvec iov[1];
struct kvec rsp_iov; struct kvec rsp_iov;
int resp_buf_type; int resp_buf_type;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = CIFS_OBREAK_OP;
server = cifs_pick_channel(ses);
cifs_dbg(FYI, "SMB2_oplock_break\n"); cifs_dbg(FYI, "SMB2_oplock_break\n");
rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server, rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
...@@ -5453,15 +5601,21 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5453,15 +5601,21 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 1;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buf_type, flags, &rsp_iov); &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) { if (rc) {
cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
cifs_dbg(FYI, "Send error in Oplock Break = %d\n", rc); cifs_dbg(FYI, "Send error in Oplock Break = %d\n", rc);
} }
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5547,9 +5701,15 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5547,9 +5701,15 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0; int rc = 0;
int resp_buftype; int resp_buftype;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
FILE_SYSTEM_POSIX_INFO *info = NULL; FILE_SYSTEM_POSIX_INFO *info = NULL;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
rc = build_qfs_info_req(&iov, tcon, server, rc = build_qfs_info_req(&iov, tcon, server,
FS_POSIX_INFORMATION, FS_POSIX_INFORMATION,
...@@ -5565,6 +5725,9 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5565,6 +5725,9 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov; rqst.rq_iov = &iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 1;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
free_qfs_info_req(&iov); free_qfs_info_req(&iov);
...@@ -5584,6 +5747,11 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5584,6 +5747,11 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
posix_qfsinf_exit: posix_qfsinf_exit:
free_rsp_buf(resp_buftype, rsp_iov.iov_base); free_rsp_buf(resp_buftype, rsp_iov.iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5598,9 +5766,15 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5598,9 +5766,15 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0; int rc = 0;
int resp_buftype; int resp_buftype;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
struct smb2_fs_full_size_info *info = NULL; struct smb2_fs_full_size_info *info = NULL;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
rc = build_qfs_info_req(&iov, tcon, server, rc = build_qfs_info_req(&iov, tcon, server,
FS_FULL_SIZE_INFORMATION, FS_FULL_SIZE_INFORMATION,
...@@ -5616,6 +5790,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5616,6 +5790,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov; rqst.rq_iov = &iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 1;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
free_qfs_info_req(&iov); free_qfs_info_req(&iov);
...@@ -5635,6 +5812,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5635,6 +5812,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
qfsinf_exit: qfsinf_exit:
free_rsp_buf(resp_buftype, rsp_iov.iov_base); free_rsp_buf(resp_buftype, rsp_iov.iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5649,9 +5831,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5649,9 +5831,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0; int rc = 0;
int resp_buftype, max_len, min_len; int resp_buftype, max_len, min_len;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses); struct TCP_Server_Info *server;
unsigned int rsp_len, offset; unsigned int rsp_len, offset;
int flags = 0; int flags = 0;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
if (level == FS_DEVICE_INFORMATION) { if (level == FS_DEVICE_INFORMATION) {
max_len = sizeof(FILE_SYSTEM_DEVICE_INFO); max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
...@@ -5683,6 +5871,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5683,6 +5871,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov; rqst.rq_iov = &iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 1;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov); &rqst, &resp_buftype, flags, &rsp_iov);
free_qfs_info_req(&iov); free_qfs_info_req(&iov);
...@@ -5720,6 +5911,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5720,6 +5911,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
qfsattr_exit: qfsattr_exit:
free_rsp_buf(resp_buftype, rsp_iov.iov_base); free_rsp_buf(resp_buftype, rsp_iov.iov_base);
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
...@@ -5737,7 +5933,13 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5737,7 +5933,13 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
unsigned int count; unsigned int count;
int flags = CIFS_NO_RSP_BUF; int flags = CIFS_NO_RSP_BUF;
unsigned int total_len; unsigned int total_len;
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); struct TCP_Server_Info *server;
int retries = 0, cur_sleep = 1;
replay_again:
/* reinitialize for possible replay */
flags = CIFS_NO_RSP_BUF;
server = cifs_pick_channel(tcon->ses);
cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock); cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
...@@ -5768,6 +5970,9 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5768,6 +5970,9 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 2; rqst.rq_nvec = 2;
if (retries)
smb2_set_replay(server, &rqst);
rc = cifs_send_recv(xid, tcon->ses, server, rc = cifs_send_recv(xid, tcon->ses, server,
&rqst, &resp_buf_type, flags, &rqst, &resp_buf_type, flags,
&rsp_iov); &rsp_iov);
...@@ -5779,6 +5984,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5779,6 +5984,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
tcon->ses->Suid, rc); tcon->ses->Suid, rc);
} }
if (is_replayable_error(rc) &&
smb2_should_replay(tcon, &retries, &cur_sleep))
goto replay_again;
return rc; return rc;
} }
......
...@@ -122,6 +122,11 @@ extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, ...@@ -122,6 +122,11 @@ extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
extern void smb2_set_next_command(struct cifs_tcon *tcon, extern void smb2_set_next_command(struct cifs_tcon *tcon,
struct smb_rqst *rqst); struct smb_rqst *rqst);
extern void smb2_set_related(struct smb_rqst *rqst); extern void smb2_set_related(struct smb_rqst *rqst);
extern void smb2_set_replay(struct TCP_Server_Info *server,
struct smb_rqst *rqst);
extern bool smb2_should_replay(struct cifs_tcon *tcon,
int *pretries,
int *pcur_sleep);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
...@@ -26,13 +26,6 @@ ...@@ -26,13 +26,6 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "../common/md4.h" #include "../common/md4.h"
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
/* following came from the other byteorder.h to avoid include conflicts */ /* following came from the other byteorder.h to avoid include conflicts */
#define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
......
...@@ -400,10 +400,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -400,10 +400,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
server->conn_id, server->hostname); server->conn_id, server->hostname);
} }
smbd_done: smbd_done:
if (rc < 0 && rc != -EINTR) /*
* there's hardly any use for the layers above to know the
* actual error code here. All they should do at this point is
* to retry the connection and hope it goes away.
*/
if (rc < 0 && rc != -EINTR && rc != -EAGAIN) {
cifs_server_dbg(VFS, "Error %d sending data on socket to server\n", cifs_server_dbg(VFS, "Error %d sending data on socket to server\n",
rc); rc);
else if (rc > 0) rc = -ECONNABORTED;
cifs_signal_cifsd_for_reconnect(server, false);
} else if (rc > 0)
rc = 0; rc = 0;
out: out:
cifs_in_send_dec(server); cifs_in_send_dec(server);
...@@ -1026,6 +1033,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) ...@@ -1026,6 +1033,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
if (!server || server->terminate) if (!server || server->terminate)
continue; continue;
if (CIFS_CHAN_NEEDS_RECONNECT(ses, i))
continue;
/* /*
* strictly speaking, we should pick up req_lock to read * strictly speaking, we should pick up req_lock to read
* server->in_flight. But it shouldn't matter much here if we * server->in_flight. But it shouldn't matter much here if we
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment