Skip to content

Commit c4f1450

Browse files
dhowellsbrauner
authored andcommitted
cachefiles, netfs: Fix write to partial block at EOF
Because it uses DIO writes, cachefiles is unable to make a write to the backing file if that write is not aligned to and sized according to the backing file's DIO block alignment. This makes it tricky to handle a write to the cache where the EOF on the network file is not correctly aligned. To get around this, netfslib attempts to tell the driver it is calling how much more data there is available beyond the EOF that it can use to pad the write (netfslib preclears the part of the folio above the EOF). However, it tries to tell the cache what the maximum length is, but doesn't calculate this correctly; and, in any case, cachefiles actually ignores the value and just skips the block. Fix this by: (1) Change the value passed to indicate the amount of extra data that can be added to the operation (now ->submit_extendable_to). This is much simpler to calculate as it's just the end of the folio minus the top of the data within the folio - rather than having to account for data spread over multiple folios. (2) Make cachefiles add some of this data if the subrequest it is given ends at the network file's i_size if the extra data is sufficient to pad out to a whole block. Signed-off-by: David Howells <[email protected]> cc: Jeff Layton <[email protected]> cc: [email protected] cc: [email protected] Link: https://lore.kernel.org/r/[email protected]/ # v2 Signed-off-by: Christian Brauner <[email protected]>
1 parent 86b374d commit c4f1450

File tree

4 files changed

+19
-6
lines changed

4 files changed

+19
-6
lines changed

fs/cachefiles/io.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ static void cachefiles_issue_write(struct netfs_io_subrequest *subreq)
648648
struct netfs_cache_resources *cres = &wreq->cache_resources;
649649
struct cachefiles_object *object = cachefiles_cres_object(cres);
650650
struct cachefiles_cache *cache = object->volume->cache;
651+
struct netfs_io_stream *stream = &wreq->io_streams[subreq->stream_nr];
651652
const struct cred *saved_cred;
652653
size_t off, pre, post, len = subreq->len;
653654
loff_t start = subreq->start;
@@ -661,6 +662,7 @@ static void cachefiles_issue_write(struct netfs_io_subrequest *subreq)
661662
if (off) {
662663
pre = CACHEFILES_DIO_BLOCK_SIZE - off;
663664
if (pre >= len) {
665+
fscache_count_dio_misfit();
664666
netfs_write_subrequest_terminated(subreq, len, false);
665667
return;
666668
}
@@ -671,10 +673,22 @@ static void cachefiles_issue_write(struct netfs_io_subrequest *subreq)
671673
}
672674

673675
/* We also need to end on the cache granularity boundary */
676+
if (start + len == wreq->i_size) {
677+
size_t part = len % CACHEFILES_DIO_BLOCK_SIZE;
678+
size_t need = CACHEFILES_DIO_BLOCK_SIZE - part;
679+
680+
if (part && stream->submit_extendable_to >= need) {
681+
len += need;
682+
subreq->len += need;
683+
subreq->io_iter.count += need;
684+
}
685+
}
686+
674687
post = len & (CACHEFILES_DIO_BLOCK_SIZE - 1);
675688
if (post) {
676689
len -= post;
677690
if (len == 0) {
691+
fscache_count_dio_misfit();
678692
netfs_write_subrequest_terminated(subreq, post, false);
679693
return;
680694
}

fs/netfs/read_pgpriv2.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
9797
if (netfs_buffer_append_folio(wreq, folio, false) < 0)
9898
return -ENOMEM;
9999

100-
cache->submit_max_len = fsize;
100+
cache->submit_extendable_to = fsize;
101101
cache->submit_off = 0;
102102
cache->submit_len = flen;
103103

@@ -112,10 +112,10 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
112112
wreq->io_iter.iov_offset = cache->submit_off;
113113

114114
atomic64_set(&wreq->issued_to, fpos + cache->submit_off);
115+
cache->submit_extendable_to = fsize - cache->submit_off;
115116
part = netfs_advance_write(wreq, cache, fpos + cache->submit_off,
116117
cache->submit_len, to_eof);
117118
cache->submit_off += part;
118-
cache->submit_max_len -= part;
119119
if (part > cache->submit_len)
120120
cache->submit_len = 0;
121121
else

fs/netfs/write_issue.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ int netfs_advance_write(struct netfs_io_request *wreq,
283283
_debug("part %zx/%zx %zx/%zx", subreq->len, stream->sreq_max_len, part, len);
284284
subreq->len += part;
285285
subreq->nr_segs++;
286+
stream->submit_extendable_to -= part;
286287

287288
if (subreq->len >= stream->sreq_max_len ||
288289
subreq->nr_segs >= stream->sreq_max_segs ||
@@ -424,15 +425,13 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
424425
*/
425426
for (int s = 0; s < NR_IO_STREAMS; s++) {
426427
stream = &wreq->io_streams[s];
427-
stream->submit_max_len = fsize;
428428
stream->submit_off = foff;
429429
stream->submit_len = flen;
430430
if ((stream->source == NETFS_WRITE_TO_CACHE && streamw) ||
431431
(stream->source == NETFS_UPLOAD_TO_SERVER &&
432432
fgroup == NETFS_FOLIO_COPY_TO_CACHE)) {
433433
stream->submit_off = UINT_MAX;
434434
stream->submit_len = 0;
435-
stream->submit_max_len = 0;
436435
}
437436
}
438437

@@ -462,10 +461,10 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
462461
wreq->io_iter.iov_offset = stream->submit_off;
463462

464463
atomic64_set(&wreq->issued_to, fpos + stream->submit_off);
464+
stream->submit_extendable_to = fsize - stream->submit_off;
465465
part = netfs_advance_write(wreq, stream, fpos + stream->submit_off,
466466
stream->submit_len, to_eof);
467467
stream->submit_off += part;
468-
stream->submit_max_len -= part;
469468
if (part > stream->submit_len)
470469
stream->submit_len = 0;
471470
else

include/linux/netfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ struct netfs_io_stream {
135135
unsigned int sreq_max_segs; /* 0 or max number of segments in an iterator */
136136
unsigned int submit_off; /* Folio offset we're submitting from */
137137
unsigned int submit_len; /* Amount of data left to submit */
138-
unsigned int submit_max_len; /* Amount I/O can be rounded up to */
138+
unsigned int submit_extendable_to; /* Amount I/O can be rounded up to */
139139
void (*prepare_write)(struct netfs_io_subrequest *subreq);
140140
void (*issue_write)(struct netfs_io_subrequest *subreq);
141141
/* Collection tracking */

0 commit comments

Comments
 (0)