netfs: Provide func to copy data to pagecache for buffered write
Provide a netfs write helper, netfs_perform_write() to buffer data to be written in the pagecache and mark the modified folios dirty. It will perform "streaming writes" for folios that aren't currently resident, if possible, storing data in partially modified folios that are marked dirty, but not uptodate. It will also tag pages as belonging to fs-specific write groups if so directed by the filesystem. This is derived from generic_perform_write(), but doesn't use ->write_begin() and ->write_end(), having that logic rolled in instead. Signed-off-by: David Howells <dhowells@redhat.com> cc: Jeff Layton <jlayton@kernel.org> cc: linux-cachefs@redhat.com cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org
This commit is contained in:
@@ -63,6 +63,7 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
|
||||
break;
|
||||
}
|
||||
if (!folio_started && test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags)) {
|
||||
trace_netfs_folio(folio, netfs_folio_trace_copy_to_cache);
|
||||
folio_start_fscache(folio);
|
||||
folio_started = true;
|
||||
}
|
||||
@@ -454,3 +455,51 @@ error:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(netfs_write_begin);
|
||||
|
||||
/*
|
||||
* Preload the data into a page we're proposing to write into.
|
||||
*/
|
||||
int netfs_prefetch_for_write(struct file *file, struct folio *folio,
|
||||
size_t offset, size_t len)
|
||||
{
|
||||
struct netfs_io_request *rreq;
|
||||
struct address_space *mapping = folio_file_mapping(folio);
|
||||
struct netfs_inode *ctx = netfs_inode(mapping->host);
|
||||
unsigned long long start = folio_pos(folio);
|
||||
size_t flen = folio_size(folio);
|
||||
int ret;
|
||||
|
||||
_enter("%zx @%llx", flen, start);
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
rreq = netfs_alloc_request(mapping, file, start, flen,
|
||||
NETFS_READ_FOR_WRITE);
|
||||
if (IS_ERR(rreq)) {
|
||||
ret = PTR_ERR(rreq);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rreq->no_unlock_folio = folio_index(folio);
|
||||
__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags);
|
||||
ret = netfs_begin_cache_read(rreq, ctx);
|
||||
if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS)
|
||||
goto error_put;
|
||||
|
||||
netfs_stat(&netfs_n_rh_write_begin);
|
||||
trace_netfs_read(rreq, start, flen, netfs_read_trace_prefetch_for_write);
|
||||
|
||||
/* Set up the output buffer */
|
||||
iov_iter_xarray(&rreq->iter, ITER_DEST, &mapping->i_pages,
|
||||
rreq->start, rreq->len);
|
||||
|
||||
ret = netfs_begin_read(rreq, true);
|
||||
netfs_put_request(rreq, false, netfs_rreq_trace_put_return);
|
||||
return ret;
|
||||
|
||||
error_put:
|
||||
netfs_put_request(rreq, false, netfs_rreq_trace_put_discard);
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user