Skip to content

Commit d1bba17

Browse files
committed
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
2 parents 3a5879d + 993d1c3 commit d1bba17

File tree

13 files changed

+467
-74
lines changed

13 files changed

+467
-74
lines changed

fs/smb/client/cached_dir.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
145145
struct cached_fid *cfid;
146146
struct cached_fids *cfids;
147147
const char *npath;
148+
int retries = 0, cur_sleep = 1;
148149

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

153154
ses = tcon->ses;
154-
server = cifs_pick_channel(ses);
155155
cfids = tcon->cfids;
156156

157-
if (!server->ops->new_lease_key)
158-
return -EIO;
159-
160157
if (cifs_sb->root == NULL)
161158
return -ENOENT;
162159

160+
replay_again:
161+
/* reinitialize for possible replay */
162+
flags = 0;
163+
oplock = SMB2_OPLOCK_LEVEL_II;
164+
server = cifs_pick_channel(ses);
165+
166+
if (!server->ops->new_lease_key)
167+
return -EIO;
168+
163169
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
164170
if (!utf16_path)
165171
return -ENOMEM;
@@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
268274
*/
269275
cfid->has_lease = true;
270276

277+
if (retries) {
278+
smb2_set_replay(server, &rqst[0]);
279+
smb2_set_replay(server, &rqst[1]);
280+
}
281+
271282
rc = compound_send_recv(xid, ses, server,
272283
flags, 2, rqst,
273284
resp_buftype, rsp_iov);
@@ -367,6 +378,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
367378
atomic_inc(&tcon->num_remote_opens);
368379
}
369380
kfree(utf16_path);
381+
382+
if (is_replayable_error(rc) &&
383+
smb2_should_replay(tcon, &retries, &cur_sleep))
384+
goto replay_again;
385+
370386
return rc;
371387
}
372388

fs/smb/client/cifsencrypt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
572572
len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
573573
UniStrupr(user);
574574
} else {
575-
memset(user, '\0', 2);
575+
*(u16 *)user = 0;
576576
}
577577

578578
rc = crypto_shash_update(ses->server->secmech.hmacmd5,

fs/smb/client/cifsfs.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb)
396396
spin_lock_init(&cifs_inode->writers_lock);
397397
cifs_inode->writers = 0;
398398
cifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
399-
cifs_inode->server_eof = 0;
399+
cifs_inode->netfs.remote_i_size = 0;
400400
cifs_inode->uniqueid = 0;
401401
cifs_inode->createtime = 0;
402402
cifs_inode->epoch = 0;
@@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
13801380
struct inode *src_inode = file_inode(src_file);
13811381
struct inode *target_inode = file_inode(dst_file);
13821382
struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode);
1383+
struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode);
13831384
struct cifsFileInfo *smb_file_src;
13841385
struct cifsFileInfo *smb_file_target;
13851386
struct cifs_tcon *src_tcon;
@@ -1428,7 +1429,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
14281429
* Advance the EOF marker after the flush above to the end of the range
14291430
* if it's short of that.
14301431
*/
1431-
if (src_cifsi->server_eof < off + len) {
1432+
if (src_cifsi->netfs.remote_i_size < off + len) {
14321433
rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);
14331434
if (rc < 0)
14341435
goto unlock;
@@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
14521453
/* Discard all the folios that overlap the destination region. */
14531454
truncate_inode_pages_range(&target_inode->i_data, fstart, fend);
14541455

1456+
fscache_invalidate(cifs_inode_cookie(target_inode), NULL,
1457+
i_size_read(target_inode), 0);
1458+
14551459
rc = file_modified(dst_file);
14561460
if (!rc) {
14571461
rc = target_tcon->ses->server->ops->copychunk_range(xid,
14581462
smb_file_src, smb_file_target, off, len, destoff);
1459-
if (rc > 0 && destoff + rc > i_size_read(target_inode))
1463+
if (rc > 0 && destoff + rc > i_size_read(target_inode)) {
14601464
truncate_setsize(target_inode, destoff + rc);
1465+
netfs_resize_file(&target_cifsi->netfs,
1466+
i_size_read(target_inode), true);
1467+
fscache_resize_cookie(cifs_inode_cookie(target_inode),
1468+
i_size_read(target_inode));
1469+
}
1470+
if (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point)
1471+
target_cifsi->netfs.zero_point = destoff + rc;
14611472
}
14621473

14631474
file_accessed(src_file);

fs/smb/client/cifsglob.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
*/
5050
#define CIFS_DEF_ACTIMEO (1 * HZ)
5151

52+
/*
53+
* max sleep time before retry to server
54+
*/
55+
#define CIFS_MAX_SLEEP 2000
56+
5257
/*
5358
* max attribute cache timeout (jiffies) - 2^30
5459
*/
@@ -1501,6 +1506,7 @@ struct cifs_writedata {
15011506
struct smbd_mr *mr;
15021507
#endif
15031508
struct cifs_credits credits;
1509+
bool replay;
15041510
};
15051511

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

1839+
static inline bool is_replayable_error(int error)
1840+
{
1841+
if (error == -EAGAIN || error == -ECONNABORTED)
1842+
return true;
1843+
return false;
1844+
}
1845+
18341846

18351847
/* cifs_get_writable_file() flags */
18361848
#define FIND_WR_ANY 0

fs/smb/client/file.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
21202120
{
21212121
loff_t end_of_write = offset + bytes_written;
21222122

2123-
if (end_of_write > cifsi->server_eof)
2124-
cifsi->server_eof = end_of_write;
2123+
if (end_of_write > cifsi->netfs.remote_i_size)
2124+
netfs_resize_file(&cifsi->netfs, end_of_write, true);
21252125
}
21262126

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

32483248
spin_lock(&inode->i_lock);
32493249
cifs_update_eof(cifsi, wdata->offset, wdata->bytes);
3250-
if (cifsi->server_eof > inode->i_size)
3251-
i_size_write(inode, cifsi->server_eof);
3250+
if (cifsi->netfs.remote_i_size > inode->i_size)
3251+
i_size_write(inode, cifsi->netfs.remote_i_size);
32523252
spin_unlock(&inode->i_lock);
32533253

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

fs/smb/client/inode.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
104104
fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
105105
mtime = inode_get_mtime(inode);
106106
if (timespec64_equal(&mtime, &fattr->cf_mtime) &&
107-
cifs_i->server_eof == fattr->cf_eof) {
107+
cifs_i->netfs.remote_i_size == fattr->cf_eof) {
108108
cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
109109
__func__, cifs_i->uniqueid);
110110
return;
@@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
194194
else
195195
clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);
196196

197-
cifs_i->server_eof = fattr->cf_eof;
197+
cifs_i->netfs.remote_i_size = fattr->cf_eof;
198198
/*
199199
* Can't safely change the file size here if the client is writing to
200200
* it due to potential races.
@@ -2858,7 +2858,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
28582858

28592859
set_size_out:
28602860
if (rc == 0) {
2861-
cifsInode->server_eof = attrs->ia_size;
2861+
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
28622862
cifs_setsize(inode, attrs->ia_size);
28632863
/*
28642864
* 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)
30113011
if ((attrs->ia_valid & ATTR_SIZE) &&
30123012
attrs->ia_size != i_size_read(inode)) {
30133013
truncate_setsize(inode, attrs->ia_size);
3014+
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
30143015
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
30153016
}
30163017

@@ -3210,6 +3211,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
32103211
if ((attrs->ia_valid & ATTR_SIZE) &&
32113212
attrs->ia_size != i_size_read(inode)) {
32123213
truncate_setsize(inode, attrs->ia_size);
3214+
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
32133215
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
32143216
}
32153217

fs/smb/client/readdir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
141141
if (likely(reparse_inode_match(inode, fattr))) {
142142
fattr->cf_mode = inode->i_mode;
143143
fattr->cf_rdev = inode->i_rdev;
144-
fattr->cf_eof = CIFS_I(inode)->server_eof;
144+
fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size;
145145
fattr->cf_symlink_target = NULL;
146146
} else {
147147
CIFS_I(inode)->time = 0;

fs/smb/client/smb2inode.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
120120
unsigned int size[2];
121121
void *data[2];
122122
int len;
123+
int retries = 0, cur_sleep = 1;
124+
125+
replay_again:
126+
/* reinitialize for possible replay */
127+
flags = 0;
128+
oplock = SMB2_OPLOCK_LEVEL_NONE;
129+
num_rqst = 0;
130+
server = cifs_pick_channel(ses);
123131

124132
vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
125133
if (vars == NULL)
126134
return -ENOMEM;
127135
rqst = &vars->rqst[0];
128136
rsp_iov = &vars->rsp_iov[0];
129137

130-
server = cifs_pick_channel(ses);
131-
132138
if (smb3_encryption_required(tcon))
133139
flags |= CIFS_TRANSFORM_REQ;
134140

@@ -463,15 +469,24 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
463469
num_rqst++;
464470

465471
if (cfile) {
472+
if (retries)
473+
for (i = 1; i < num_rqst - 2; i++)
474+
smb2_set_replay(server, &rqst[i]);
475+
466476
rc = compound_send_recv(xid, ses, server,
467477
flags, num_rqst - 2,
468478
&rqst[1], &resp_buftype[1],
469479
&rsp_iov[1]);
470-
} else
480+
} else {
481+
if (retries)
482+
for (i = 0; i < num_rqst; i++)
483+
smb2_set_replay(server, &rqst[i]);
484+
471485
rc = compound_send_recv(xid, ses, server,
472486
flags, num_rqst,
473487
rqst, resp_buftype,
474488
rsp_iov);
489+
}
475490

476491
finished:
477492
num_rqst = 0;
@@ -620,9 +635,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
620635
}
621636
SMB2_close_free(&rqst[num_rqst]);
622637

623-
if (cfile)
624-
cifsFileInfo_put(cfile);
625-
626638
num_cmds += 2;
627639
if (out_iov && out_buftype) {
628640
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,
632644
for (i = 0; i < num_cmds; i++)
633645
free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
634646
}
647+
num_cmds -= 2; /* correct num_cmds as there could be a retry */
635648
kfree(vars);
649+
650+
if (is_replayable_error(rc) &&
651+
smb2_should_replay(tcon, &retries, &cur_sleep))
652+
goto replay_again;
653+
654+
if (cfile)
655+
cifsFileInfo_put(cfile);
656+
636657
return rc;
637658
}
638659

0 commit comments

Comments
 (0)