Skip to content

Commit 6b9ffc4

Browse files
committed
Merge tag 'v6.11-rc5-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - copy_file_range fix - two read fixes including read past end of file rc fix and read retry crediting fix - falloc zero range fix * tag 'v6.11-rc5-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Fix FALLOC_FL_ZERO_RANGE to preflush buffered part of target region cifs: Fix copy offload to flush destination region netfs, cifs: Fix handling of short DIO read cifs: Fix lack of credit renegotiation on read retry
2 parents a4c7631 + 91d1dfa commit 6b9ffc4

File tree

8 files changed

+94
-45
lines changed

8 files changed

+94
-45
lines changed

fs/netfs/io.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,15 @@ static bool netfs_rreq_perform_resubmissions(struct netfs_io_request *rreq)
306306
break;
307307
subreq->source = NETFS_DOWNLOAD_FROM_SERVER;
308308
subreq->error = 0;
309+
__set_bit(NETFS_SREQ_RETRYING, &subreq->flags);
309310
netfs_stat(&netfs_n_rh_download_instead);
310311
trace_netfs_sreq(subreq, netfs_sreq_trace_download_instead);
311312
netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
312313
atomic_inc(&rreq->nr_outstanding);
313314
netfs_reset_subreq_iter(rreq, subreq);
314315
netfs_read_from_server(rreq, subreq);
315316
} else if (test_bit(NETFS_SREQ_SHORT_IO, &subreq->flags)) {
317+
__set_bit(NETFS_SREQ_RETRYING, &subreq->flags);
316318
netfs_reset_subreq_iter(rreq, subreq);
317319
netfs_rreq_short_read(rreq, subreq);
318320
}
@@ -366,7 +368,8 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq)
366368
if (subreq->error || subreq->transferred == 0)
367369
break;
368370
transferred += subreq->transferred;
369-
if (subreq->transferred < subreq->len)
371+
if (subreq->transferred < subreq->len ||
372+
test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags))
370373
break;
371374
}
372375

@@ -501,7 +504,8 @@ void netfs_subreq_terminated(struct netfs_io_subrequest *subreq,
501504

502505
subreq->error = 0;
503506
subreq->transferred += transferred_or_error;
504-
if (subreq->transferred < subreq->len)
507+
if (subreq->transferred < subreq->len &&
508+
!test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags))
505509
goto incomplete;
506510

507511
complete:
@@ -780,10 +784,13 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
780784
TASK_UNINTERRUPTIBLE);
781785

782786
ret = rreq->error;
783-
if (ret == 0 && rreq->submitted < rreq->len &&
784-
rreq->origin != NETFS_DIO_READ) {
785-
trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read);
786-
ret = -EIO;
787+
if (ret == 0) {
788+
if (rreq->origin == NETFS_DIO_READ) {
789+
ret = rreq->transferred;
790+
} else if (rreq->submitted < rreq->len) {
791+
trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read);
792+
ret = -EIO;
793+
}
787794
}
788795
} else {
789796
/* If we decrement nr_outstanding to 0, the ref belongs to us. */

fs/smb/client/cifsfs.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,6 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
13411341
struct cifsFileInfo *smb_file_target;
13421342
struct cifs_tcon *src_tcon;
13431343
struct cifs_tcon *target_tcon;
1344-
unsigned long long destend, fstart, fend;
13451344
ssize_t rc;
13461345

13471346
cifs_dbg(FYI, "copychunk range\n");
@@ -1391,25 +1390,13 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
13911390
goto unlock;
13921391
}
13931392

1394-
destend = destoff + len - 1;
1395-
1396-
/* Flush the folios at either end of the destination range to prevent
1397-
* accidental loss of dirty data outside of the range.
1393+
/* Flush and invalidate all the folios in the destination region. If
1394+
* the copy was successful, then some of the flush is extra overhead,
1395+
* but we need to allow for the copy failing in some way (eg. ENOSPC).
13981396
*/
1399-
fstart = destoff;
1400-
fend = destend;
1401-
1402-
rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true);
1397+
rc = filemap_invalidate_inode(target_inode, true, destoff, destoff + len - 1);
14031398
if (rc)
14041399
goto unlock;
1405-
rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false);
1406-
if (rc)
1407-
goto unlock;
1408-
if (fend > target_cifsi->netfs.zero_point)
1409-
target_cifsi->netfs.zero_point = fend + 1;
1410-
1411-
/* Discard all the folios that overlap the destination region. */
1412-
truncate_inode_pages_range(&target_inode->i_data, fstart, fend);
14131400

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

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,7 @@ struct cifs_io_subrequest {
14851485
struct cifs_io_request *req;
14861486
};
14871487
ssize_t got_bytes;
1488+
size_t actual_len;
14881489
unsigned int xid;
14891490
int result;
14901491
bool have_xid;

fs/smb/client/file.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static void cifs_issue_write(struct netfs_io_subrequest *subreq)
111111
goto fail;
112112
}
113113

114+
wdata->actual_len = wdata->subreq.len;
114115
rc = adjust_credits(wdata->server, wdata, cifs_trace_rw_credits_issue_write_adjust);
115116
if (rc)
116117
goto fail;
@@ -153,7 +154,7 @@ static bool cifs_clamp_length(struct netfs_io_subrequest *subreq)
153154
struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq);
154155
struct TCP_Server_Info *server = req->server;
155156
struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb);
156-
size_t rsize = 0;
157+
size_t rsize;
157158
int rc;
158159

159160
rdata->xid = get_xid();
@@ -166,8 +167,8 @@ static bool cifs_clamp_length(struct netfs_io_subrequest *subreq)
166167
cifs_sb->ctx);
167168

168169

169-
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize,
170-
&rdata->credits);
170+
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
171+
&rsize, &rdata->credits);
171172
if (rc) {
172173
subreq->error = rc;
173174
return false;
@@ -183,7 +184,8 @@ static bool cifs_clamp_length(struct netfs_io_subrequest *subreq)
183184
server->credits, server->in_flight, 0,
184185
cifs_trace_rw_credits_read_submit);
185186

186-
subreq->len = min_t(size_t, subreq->len, rsize);
187+
subreq->len = umin(subreq->len, rsize);
188+
rdata->actual_len = subreq->len;
187189

188190
#ifdef CONFIG_CIFS_SMB_DIRECT
189191
if (server->smbd_conn)
@@ -203,12 +205,39 @@ static void cifs_req_issue_read(struct netfs_io_subrequest *subreq)
203205
struct netfs_io_request *rreq = subreq->rreq;
204206
struct cifs_io_subrequest *rdata = container_of(subreq, struct cifs_io_subrequest, subreq);
205207
struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq);
208+
struct TCP_Server_Info *server = req->server;
209+
struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb);
206210
int rc = 0;
207211

208212
cifs_dbg(FYI, "%s: op=%08x[%x] mapping=%p len=%zu/%zu\n",
209213
__func__, rreq->debug_id, subreq->debug_index, rreq->mapping,
210214
subreq->transferred, subreq->len);
211215

216+
if (test_bit(NETFS_SREQ_RETRYING, &subreq->flags)) {
217+
/*
218+
* As we're issuing a retry, we need to negotiate some new
219+
* credits otherwise the server may reject the op with
220+
* INVALID_PARAMETER. Note, however, we may get back less
221+
* credit than we need to complete the op, in which case, we
222+
* shorten the op and rely on additional rounds of retry.
223+
*/
224+
size_t rsize = umin(subreq->len - subreq->transferred,
225+
cifs_sb->ctx->rsize);
226+
227+
rc = server->ops->wait_mtu_credits(server, rsize, &rdata->actual_len,
228+
&rdata->credits);
229+
if (rc)
230+
goto out;
231+
232+
rdata->credits.in_flight_check = 1;
233+
234+
trace_smb3_rw_credits(rdata->rreq->debug_id,
235+
rdata->subreq.debug_index,
236+
rdata->credits.value,
237+
server->credits, server->in_flight, 0,
238+
cifs_trace_rw_credits_read_resubmit);
239+
}
240+
212241
if (req->cfile->invalidHandle) {
213242
do {
214243
rc = cifs_reopen_file(req->cfile, true);

fs/smb/client/smb2ops.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
301301
unsigned int /*enum smb3_rw_credits_trace*/ trace)
302302
{
303303
struct cifs_credits *credits = &subreq->credits;
304-
int new_val = DIV_ROUND_UP(subreq->subreq.len, SMB2_MAX_BUFFER_SIZE);
304+
int new_val = DIV_ROUND_UP(subreq->actual_len, SMB2_MAX_BUFFER_SIZE);
305305
int scredits, in_flight;
306306

307307
if (!credits->value || credits->value == new_val)
@@ -3237,13 +3237,15 @@ static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
32373237
}
32383238

32393239
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
3240-
loff_t offset, loff_t len, bool keep_size)
3240+
unsigned long long offset, unsigned long long len,
3241+
bool keep_size)
32413242
{
32423243
struct cifs_ses *ses = tcon->ses;
32433244
struct inode *inode = file_inode(file);
32443245
struct cifsInodeInfo *cifsi = CIFS_I(inode);
32453246
struct cifsFileInfo *cfile = file->private_data;
3246-
unsigned long long new_size;
3247+
struct netfs_inode *ictx = netfs_inode(inode);
3248+
unsigned long long i_size, new_size, remote_size;
32473249
long rc;
32483250
unsigned int xid;
32493251

@@ -3255,6 +3257,16 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
32553257
inode_lock(inode);
32563258
filemap_invalidate_lock(inode->i_mapping);
32573259

3260+
i_size = i_size_read(inode);
3261+
remote_size = ictx->remote_i_size;
3262+
if (offset + len >= remote_size && offset < i_size) {
3263+
unsigned long long top = umin(offset + len, i_size);
3264+
3265+
rc = filemap_write_and_wait_range(inode->i_mapping, offset, top - 1);
3266+
if (rc < 0)
3267+
goto zero_range_exit;
3268+
}
3269+
32583270
/*
32593271
* We zero the range through ioctl, so we need remove the page caches
32603272
* first, otherwise the data may be inconsistent with the server.

fs/smb/client/smb2pdu.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4507,6 +4507,7 @@ static void
45074507
smb2_readv_callback(struct mid_q_entry *mid)
45084508
{
45094509
struct cifs_io_subrequest *rdata = mid->callback_data;
4510+
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
45104511
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
45114512
struct TCP_Server_Info *server = rdata->server;
45124513
struct smb2_hdr *shdr =
@@ -4529,9 +4530,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
45294530
"rdata server %p != mid server %p",
45304531
rdata->server, mid->server);
45314532

4532-
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
4533+
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu/%zu\n",
45334534
__func__, mid->mid, mid->mid_state, rdata->result,
4534-
rdata->subreq.len);
4535+
rdata->actual_len, rdata->subreq.len - rdata->subreq.transferred);
45354536

45364537
switch (mid->mid_state) {
45374538
case MID_RESPONSE_RECEIVED:
@@ -4585,22 +4586,29 @@ smb2_readv_callback(struct mid_q_entry *mid)
45854586
rdata->subreq.debug_index,
45864587
rdata->xid,
45874588
rdata->req->cfile->fid.persistent_fid,
4588-
tcon->tid, tcon->ses->Suid, rdata->subreq.start,
4589-
rdata->subreq.len, rdata->result);
4589+
tcon->tid, tcon->ses->Suid,
4590+
rdata->subreq.start + rdata->subreq.transferred,
4591+
rdata->actual_len,
4592+
rdata->result);
45904593
} else
45914594
trace_smb3_read_done(rdata->rreq->debug_id,
45924595
rdata->subreq.debug_index,
45934596
rdata->xid,
45944597
rdata->req->cfile->fid.persistent_fid,
45954598
tcon->tid, tcon->ses->Suid,
4596-
rdata->subreq.start, rdata->got_bytes);
4599+
rdata->subreq.start + rdata->subreq.transferred,
4600+
rdata->got_bytes);
45974601

45984602
if (rdata->result == -ENODATA) {
4599-
/* We may have got an EOF error because fallocate
4600-
* failed to enlarge the file.
4601-
*/
4602-
if (rdata->subreq.start < rdata->subreq.rreq->i_size)
4603+
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
4604+
rdata->result = 0;
4605+
} else {
4606+
if (rdata->got_bytes < rdata->actual_len &&
4607+
rdata->subreq.start + rdata->subreq.transferred + rdata->got_bytes ==
4608+
ictx->remote_i_size) {
4609+
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
46034610
rdata->result = 0;
4611+
}
46044612
}
46054613
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
46064614
server->credits, server->in_flight,
@@ -4621,6 +4629,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
46214629
{
46224630
int rc, flags = 0;
46234631
char *buf;
4632+
struct netfs_io_subrequest *subreq = &rdata->subreq;
46244633
struct smb2_hdr *shdr;
46254634
struct cifs_io_parms io_parms;
46264635
struct smb_rqst rqst = { .rq_iov = rdata->iov,
@@ -4631,15 +4640,15 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
46314640
int credit_request;
46324641

46334642
cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
4634-
__func__, rdata->subreq.start, rdata->subreq.len);
4643+
__func__, subreq->start, subreq->len);
46354644

46364645
if (!rdata->server)
46374646
rdata->server = cifs_pick_channel(tcon->ses);
46384647

46394648
io_parms.tcon = tlink_tcon(rdata->req->cfile->tlink);
46404649
io_parms.server = server = rdata->server;
4641-
io_parms.offset = rdata->subreq.start;
4642-
io_parms.length = rdata->subreq.len;
4650+
io_parms.offset = subreq->start + subreq->transferred;
4651+
io_parms.length = rdata->actual_len;
46434652
io_parms.persistent_fid = rdata->req->cfile->fid.persistent_fid;
46444653
io_parms.volatile_fid = rdata->req->cfile->fid.volatile_fid;
46454654
io_parms.pid = rdata->req->pid;
@@ -4654,11 +4663,13 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
46544663

46554664
rdata->iov[0].iov_base = buf;
46564665
rdata->iov[0].iov_len = total_len;
4666+
rdata->got_bytes = 0;
4667+
rdata->result = 0;
46574668

46584669
shdr = (struct smb2_hdr *)buf;
46594670

46604671
if (rdata->credits.value > 0) {
4661-
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->subreq.len,
4672+
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->actual_len,
46624673
SMB2_MAX_BUFFER_SIZE));
46634674
credit_request = le16_to_cpu(shdr->CreditCharge) + 8;
46644675
if (server->credits >= server->max_credits)
@@ -4682,11 +4693,11 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
46824693
if (rc) {
46834694
cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
46844695
trace_smb3_read_err(rdata->rreq->debug_id,
4685-
rdata->subreq.debug_index,
4696+
subreq->debug_index,
46864697
rdata->xid, io_parms.persistent_fid,
46874698
io_parms.tcon->tid,
46884699
io_parms.tcon->ses->Suid,
4689-
io_parms.offset, io_parms.length, rc);
4700+
io_parms.offset, rdata->actual_len, rc);
46904701
}
46914702

46924703
async_readv_out:

fs/smb/client/trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
EM(cifs_trace_rw_credits_old_session, "old-session") \
3131
EM(cifs_trace_rw_credits_read_response_add, "rd-resp-add") \
3232
EM(cifs_trace_rw_credits_read_response_clear, "rd-resp-clr") \
33+
EM(cifs_trace_rw_credits_read_resubmit, "rd-resubmit") \
3334
EM(cifs_trace_rw_credits_read_submit, "rd-submit ") \
3435
EM(cifs_trace_rw_credits_write_prepare, "wr-prepare ") \
3536
EM(cifs_trace_rw_credits_write_response_add, "wr-resp-add") \

include/linux/netfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ struct netfs_io_subrequest {
198198
#define NETFS_SREQ_NEED_RETRY 9 /* Set if the filesystem requests a retry */
199199
#define NETFS_SREQ_RETRYING 10 /* Set if we're retrying */
200200
#define NETFS_SREQ_FAILED 11 /* Set if the subreq failed unretryably */
201+
#define NETFS_SREQ_HIT_EOF 12 /* Set if we hit the EOF */
201202
};
202203

203204
enum netfs_io_origin {

0 commit comments

Comments
 (0)