mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
netfs: Add a function to consolidate beginning a read
Add a function to do the steps needed to begin a read request, allowing this code to be removed from several other functions and consolidated. Changes ======= ver #2) - Move before the unstaticking patch so that some functions can be left static. - Set uninitialised return code in netfs_begin_read()[1][2]. - Fixed a refleak caused by non-removal of a get from netfs_write_begin() when the request submission code got moved to netfs_begin_read(). - Use INIT_WORK() to (re-)init the request work_struct[3]. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> cc: linux-cachefs@redhat.com Link: https://lore.kernel.org/r/20220303163826.1120936-1-nathan@kernel.org/ [1] Link: https://lore.kernel.org/r/20220303235647.1297171-1-colin.i.king@gmail.com/ [2] Link: https://lore.kernel.org/r/9d69be49081bccff44260e4c6e0049c63d6d04a1.camel@redhat.com/ [3] Link: https://lore.kernel.org/r/164623004355.3564931.7275693529042495641.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/164678214287.1200972.16734134007649832160.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/164692911113.2099075.1060868473229451371.stgit@warthog.procyon.org.uk/ # v3
This commit is contained in:
parent
bc899ee1c8
commit
4090b31422
|
|
@ -39,7 +39,7 @@ static inline void netfs_see_request(struct netfs_io_request *rreq,
|
||||||
*/
|
*/
|
||||||
extern unsigned int netfs_debug;
|
extern unsigned int netfs_debug;
|
||||||
|
|
||||||
void netfs_rreq_work(struct work_struct *work);
|
int netfs_begin_read(struct netfs_io_request *rreq, bool sync);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stats.c
|
* stats.c
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
|
||||||
rreq->i_size = i_size_read(inode);
|
rreq->i_size = i_size_read(inode);
|
||||||
rreq->debug_id = atomic_inc_return(&debug_ids);
|
rreq->debug_id = atomic_inc_return(&debug_ids);
|
||||||
INIT_LIST_HEAD(&rreq->subrequests);
|
INIT_LIST_HEAD(&rreq->subrequests);
|
||||||
INIT_WORK(&rreq->work, netfs_rreq_work);
|
|
||||||
refcount_set(&rreq->ref, 1);
|
refcount_set(&rreq->ref, 1);
|
||||||
__set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
|
__set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
|
||||||
if (rreq->netfs_ops->init_request) {
|
if (rreq->netfs_ops->init_request) {
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ static void netfs_rreq_assess(struct netfs_io_request *rreq, bool was_async)
|
||||||
netfs_rreq_completed(rreq, was_async);
|
netfs_rreq_completed(rreq, was_async);
|
||||||
}
|
}
|
||||||
|
|
||||||
void netfs_rreq_work(struct work_struct *work)
|
static void netfs_rreq_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct netfs_io_request *rreq =
|
struct netfs_io_request *rreq =
|
||||||
container_of(work, struct netfs_io_request, work);
|
container_of(work, struct netfs_io_request, work);
|
||||||
|
|
@ -688,6 +688,69 @@ static bool netfs_rreq_submit_slice(struct netfs_io_request *rreq,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Begin the process of reading in a chunk of data, where that data may be
|
||||||
|
* stitched together from multiple sources, including multiple servers and the
|
||||||
|
* local cache.
|
||||||
|
*/
|
||||||
|
int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
|
||||||
|
{
|
||||||
|
unsigned int debug_index = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
_enter("R=%x %llx-%llx",
|
||||||
|
rreq->debug_id, rreq->start, rreq->start + rreq->len - 1);
|
||||||
|
|
||||||
|
if (rreq->len == 0) {
|
||||||
|
pr_err("Zero-sized read [R=%x]\n", rreq->debug_id);
|
||||||
|
netfs_put_request(rreq, false, netfs_rreq_trace_put_zero_len);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_WORK(&rreq->work, netfs_rreq_work);
|
||||||
|
|
||||||
|
if (sync)
|
||||||
|
netfs_get_request(rreq, netfs_rreq_trace_get_hold);
|
||||||
|
|
||||||
|
/* Chop the read into slices according to what the cache and the netfs
|
||||||
|
* want and submit each one.
|
||||||
|
*/
|
||||||
|
atomic_set(&rreq->nr_outstanding, 1);
|
||||||
|
do {
|
||||||
|
if (!netfs_rreq_submit_slice(rreq, &debug_index))
|
||||||
|
break;
|
||||||
|
|
||||||
|
} while (rreq->submitted < rreq->len);
|
||||||
|
|
||||||
|
if (sync) {
|
||||||
|
/* Keep nr_outstanding incremented so that the ref always belongs to
|
||||||
|
* us, and the service code isn't punted off to a random thread pool to
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
wait_var_event(&rreq->nr_outstanding,
|
||||||
|
atomic_read(&rreq->nr_outstanding) == 1);
|
||||||
|
netfs_rreq_assess(rreq, false);
|
||||||
|
if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags))
|
||||||
|
break;
|
||||||
|
cond_resched();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rreq->error;
|
||||||
|
if (ret == 0 && rreq->submitted < rreq->len) {
|
||||||
|
trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read);
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
netfs_put_request(rreq, false, netfs_rreq_trace_put_hold);
|
||||||
|
} else {
|
||||||
|
/* If we decrement nr_outstanding to 0, the ref belongs to us. */
|
||||||
|
if (atomic_dec_and_test(&rreq->nr_outstanding))
|
||||||
|
netfs_rreq_assess(rreq, false);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void netfs_cache_expand_readahead(struct netfs_io_request *rreq,
|
static void netfs_cache_expand_readahead(struct netfs_io_request *rreq,
|
||||||
loff_t *_start, size_t *_len, loff_t i_size)
|
loff_t *_start, size_t *_len, loff_t i_size)
|
||||||
{
|
{
|
||||||
|
|
@ -750,7 +813,6 @@ void netfs_readahead(struct readahead_control *ractl)
|
||||||
{
|
{
|
||||||
struct netfs_io_request *rreq;
|
struct netfs_io_request *rreq;
|
||||||
struct netfs_i_context *ctx = netfs_i_context(ractl->mapping->host);
|
struct netfs_i_context *ctx = netfs_i_context(ractl->mapping->host);
|
||||||
unsigned int debug_index = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("%lx,%x", readahead_index(ractl), readahead_count(ractl));
|
_enter("%lx,%x", readahead_index(ractl), readahead_count(ractl));
|
||||||
|
|
@ -777,22 +839,13 @@ void netfs_readahead(struct readahead_control *ractl)
|
||||||
|
|
||||||
netfs_rreq_expand(rreq, ractl);
|
netfs_rreq_expand(rreq, ractl);
|
||||||
|
|
||||||
atomic_set(&rreq->nr_outstanding, 1);
|
|
||||||
do {
|
|
||||||
if (!netfs_rreq_submit_slice(rreq, &debug_index))
|
|
||||||
break;
|
|
||||||
|
|
||||||
} while (rreq->submitted < rreq->len);
|
|
||||||
|
|
||||||
/* Drop the refs on the folios here rather than in the cache or
|
/* Drop the refs on the folios here rather than in the cache or
|
||||||
* filesystem. The locks will be dropped in netfs_rreq_unlock().
|
* filesystem. The locks will be dropped in netfs_rreq_unlock().
|
||||||
*/
|
*/
|
||||||
while (readahead_folio(ractl))
|
while (readahead_folio(ractl))
|
||||||
;
|
;
|
||||||
|
|
||||||
/* If we decrement nr_outstanding to 0, the ref belongs to us. */
|
netfs_begin_read(rreq, false);
|
||||||
if (atomic_dec_and_test(&rreq->nr_outstanding))
|
|
||||||
netfs_rreq_assess(rreq, false);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cleanup_free:
|
cleanup_free:
|
||||||
|
|
@ -821,7 +874,6 @@ int netfs_readpage(struct file *file, struct page *subpage)
|
||||||
struct address_space *mapping = folio->mapping;
|
struct address_space *mapping = folio->mapping;
|
||||||
struct netfs_io_request *rreq;
|
struct netfs_io_request *rreq;
|
||||||
struct netfs_i_context *ctx = netfs_i_context(mapping->host);
|
struct netfs_i_context *ctx = netfs_i_context(mapping->host);
|
||||||
unsigned int debug_index = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("%lx", folio_index(folio));
|
_enter("%lx", folio_index(folio));
|
||||||
|
|
@ -836,42 +888,16 @@ int netfs_readpage(struct file *file, struct page *subpage)
|
||||||
|
|
||||||
if (ctx->ops->begin_cache_operation) {
|
if (ctx->ops->begin_cache_operation) {
|
||||||
ret = ctx->ops->begin_cache_operation(rreq);
|
ret = ctx->ops->begin_cache_operation(rreq);
|
||||||
if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) {
|
if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS)
|
||||||
folio_unlock(folio);
|
goto discard;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
netfs_stat(&netfs_n_rh_readpage);
|
netfs_stat(&netfs_n_rh_readpage);
|
||||||
trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage);
|
trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage);
|
||||||
|
return netfs_begin_read(rreq, true);
|
||||||
|
|
||||||
netfs_get_request(rreq, netfs_rreq_trace_get_hold);
|
discard:
|
||||||
|
netfs_put_request(rreq, false, netfs_rreq_trace_put_discard);
|
||||||
atomic_set(&rreq->nr_outstanding, 1);
|
|
||||||
do {
|
|
||||||
if (!netfs_rreq_submit_slice(rreq, &debug_index))
|
|
||||||
break;
|
|
||||||
|
|
||||||
} while (rreq->submitted < rreq->len);
|
|
||||||
|
|
||||||
/* Keep nr_outstanding incremented so that the ref always belongs to us, and
|
|
||||||
* the service code isn't punted off to a random thread pool to
|
|
||||||
* process.
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
wait_var_event(&rreq->nr_outstanding,
|
|
||||||
atomic_read(&rreq->nr_outstanding) == 1);
|
|
||||||
netfs_rreq_assess(rreq, false);
|
|
||||||
} while (test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags));
|
|
||||||
|
|
||||||
ret = rreq->error;
|
|
||||||
if (ret == 0 && rreq->submitted < rreq->len) {
|
|
||||||
trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_readpage);
|
|
||||||
ret = -EIO;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
netfs_put_request(rreq, false, netfs_rreq_trace_put_hold);
|
|
||||||
return ret;
|
|
||||||
alloc_error:
|
alloc_error:
|
||||||
folio_unlock(folio);
|
folio_unlock(folio);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -966,7 +992,7 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
struct netfs_io_request *rreq;
|
struct netfs_io_request *rreq;
|
||||||
struct netfs_i_context *ctx = netfs_i_context(file_inode(file ));
|
struct netfs_i_context *ctx = netfs_i_context(file_inode(file ));
|
||||||
struct folio *folio;
|
struct folio *folio;
|
||||||
unsigned int debug_index = 0, fgp_flags;
|
unsigned int fgp_flags;
|
||||||
pgoff_t index = pos >> PAGE_SHIFT;
|
pgoff_t index = pos >> PAGE_SHIFT;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1029,39 +1055,13 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
*/
|
*/
|
||||||
ractl._nr_pages = folio_nr_pages(folio);
|
ractl._nr_pages = folio_nr_pages(folio);
|
||||||
netfs_rreq_expand(rreq, &ractl);
|
netfs_rreq_expand(rreq, &ractl);
|
||||||
netfs_get_request(rreq, netfs_rreq_trace_get_hold);
|
|
||||||
|
|
||||||
/* We hold the folio locks, so we can drop the references */
|
/* We hold the folio locks, so we can drop the references */
|
||||||
folio_get(folio);
|
folio_get(folio);
|
||||||
while (readahead_folio(&ractl))
|
while (readahead_folio(&ractl))
|
||||||
;
|
;
|
||||||
|
|
||||||
atomic_set(&rreq->nr_outstanding, 1);
|
ret = netfs_begin_read(rreq, true);
|
||||||
do {
|
|
||||||
if (!netfs_rreq_submit_slice(rreq, &debug_index))
|
|
||||||
break;
|
|
||||||
|
|
||||||
} while (rreq->submitted < rreq->len);
|
|
||||||
|
|
||||||
/* Keep nr_outstanding incremented so that the ref always belongs to
|
|
||||||
* us, and the service code isn't punted off to a random thread pool to
|
|
||||||
* process.
|
|
||||||
*/
|
|
||||||
for (;;) {
|
|
||||||
wait_var_event(&rreq->nr_outstanding,
|
|
||||||
atomic_read(&rreq->nr_outstanding) == 1);
|
|
||||||
netfs_rreq_assess(rreq, false);
|
|
||||||
if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags))
|
|
||||||
break;
|
|
||||||
cond_resched();
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rreq->error;
|
|
||||||
if (ret == 0 && rreq->submitted < rreq->len) {
|
|
||||||
trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_write_begin);
|
|
||||||
ret = -EIO;
|
|
||||||
}
|
|
||||||
netfs_put_request(rreq, false, netfs_rreq_trace_put_hold);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,17 +56,18 @@
|
||||||
EM(netfs_fail_check_write_begin, "check-write-begin") \
|
EM(netfs_fail_check_write_begin, "check-write-begin") \
|
||||||
EM(netfs_fail_copy_to_cache, "copy-to-cache") \
|
EM(netfs_fail_copy_to_cache, "copy-to-cache") \
|
||||||
EM(netfs_fail_read, "read") \
|
EM(netfs_fail_read, "read") \
|
||||||
EM(netfs_fail_short_readpage, "short-readpage") \
|
EM(netfs_fail_short_read, "short-read") \
|
||||||
EM(netfs_fail_short_write_begin, "short-write-begin") \
|
|
||||||
E_(netfs_fail_prepare_write, "prep-write")
|
E_(netfs_fail_prepare_write, "prep-write")
|
||||||
|
|
||||||
#define netfs_rreq_ref_traces \
|
#define netfs_rreq_ref_traces \
|
||||||
EM(netfs_rreq_trace_get_hold, "GET HOLD ") \
|
EM(netfs_rreq_trace_get_hold, "GET HOLD ") \
|
||||||
EM(netfs_rreq_trace_get_subreq, "GET SUBREQ ") \
|
EM(netfs_rreq_trace_get_subreq, "GET SUBREQ ") \
|
||||||
EM(netfs_rreq_trace_put_complete, "PUT COMPLT ") \
|
EM(netfs_rreq_trace_put_complete, "PUT COMPLT ") \
|
||||||
|
EM(netfs_rreq_trace_put_discard, "PUT DISCARD") \
|
||||||
EM(netfs_rreq_trace_put_failed, "PUT FAILED ") \
|
EM(netfs_rreq_trace_put_failed, "PUT FAILED ") \
|
||||||
EM(netfs_rreq_trace_put_hold, "PUT HOLD ") \
|
EM(netfs_rreq_trace_put_hold, "PUT HOLD ") \
|
||||||
EM(netfs_rreq_trace_put_subreq, "PUT SUBREQ ") \
|
EM(netfs_rreq_trace_put_subreq, "PUT SUBREQ ") \
|
||||||
|
EM(netfs_rreq_trace_put_zero_len, "PUT ZEROLEN") \
|
||||||
E_(netfs_rreq_trace_new, "NEW ")
|
E_(netfs_rreq_trace_new, "NEW ")
|
||||||
|
|
||||||
#define netfs_sreq_ref_traces \
|
#define netfs_sreq_ref_traces \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user