[PATCH RFC 1/9] cachefiles: improve FSCACHE_COOKIE_NO_DATA_TO_READ optimization

From: Jingbo Xu
Date: Mon Aug 01 2022 - 23:04:05 EST


In the following introduced content map feature,
cachefiles_prepare_[read|write] can query if the requested range is
cached through either SEEK_[DATA|HOLE] llseek or a self maintained
bitmap according to object->content_info.

For already existing backing files, content_info can be derived from the
xattr of the backing file. While for newly created tmpfile, content_info
is initialized when the backing file is written for the first time. This
time sequence requires FSCACHE_COOKIE_NO_DATA_TO_READ optimization, so
that llseek will only be called after the first write, i.e. after
content_info has been initializaed.

This patch includes following changes:

1. Enable NO_DATA optimization in cachefiles_prepare_[read|write].

2. Clear FSCACHE_COOKIE_NO_DATA_TO_READ on first write to the backing
file.

When working in non-on-demand mode, FSCACHE_COOKIE_NO_DATA_TO_READ is
cleared when a_ops->release_folio() called. While for on-demand mode,
there's a retry logic in cachefiles_prepare_read(), i.e. the requested
range will be checked for the second time after the on-demand read, thus
FSCACHE_COOKIE_NO_DATA_TO_READ needs to be cleared for on-demand mode
once write completes.

3. Improve the setting/clearing of FSCACHE_COOKIE_NO_DATA_TO_READ in
on-demand mode.

Since now we rely on NO_DATA optimization when the backing file is
actually tmpfile, the setting of FSCACHE_COOKIE_NO_DATA_TO_READ flag in
on-demand mode is delayed until the size of the backing file is acquired
when copen completes, so that FSCACHE_COOKIE_NO_DATA_TO_READ flag of
tmpfile can be retained.

Signed-off-by: Jingbo Xu <jefflexu@xxxxxxxxxxxxxxxxx>
---
fs/cachefiles/io.c | 20 +++++++++++++-------
fs/cachefiles/ondemand.c | 5 +----
fs/fscache/cookie.c | 2 +-
3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c
index 000a28f46e59..b513d9bf81f1 100644
--- a/fs/cachefiles/io.c
+++ b/fs/cachefiles/io.c
@@ -255,6 +255,7 @@ static void cachefiles_write_complete(struct kiocb *iocb, long ret)
{
struct cachefiles_kiocb *ki = container_of(iocb, struct cachefiles_kiocb, iocb);
struct cachefiles_object *object = ki->object;
+ struct fscache_cookie *cookie = object->cookie;
struct inode *inode = file_inode(ki->iocb.ki_filp);

_enter("%ld", ret);
@@ -269,6 +270,9 @@ static void cachefiles_write_complete(struct kiocb *iocb, long ret)

atomic_long_sub(ki->b_writing, &object->volume->cache->b_writing);
set_bit(FSCACHE_COOKIE_HAVE_DATA, &object->cookie->flags);
+ if (cookie->advice & FSCACHE_ADV_WANT_CACHE_SIZE &&
+ test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags))
+ clear_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
if (ki->term_func)
ki->term_func(ki->term_func_priv, ret, ki->was_async);
cachefiles_put_kiocb(ki);
@@ -413,13 +417,6 @@ static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *
goto out_no_object;
}

- if (test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags)) {
- __set_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags);
- why = cachefiles_trace_read_no_data;
- if (!test_bit(NETFS_SREQ_ONDEMAND, &subreq->flags))
- goto out_no_object;
- }
-
/* The object and the file may be being created in the background. */
if (!file) {
why = cachefiles_trace_read_no_file;
@@ -434,6 +431,11 @@ static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *
object = cachefiles_cres_object(cres);
cache = object->volume->cache;
cachefiles_begin_secure(cache, &saved_cred);
+
+ if (test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags)) {
+ why = cachefiles_trace_read_no_data;
+ goto download_and_store;
+ }
retry:
off = cachefiles_inject_read_error();
if (off == 0)
@@ -510,6 +512,7 @@ int __cachefiles_prepare_write(struct cachefiles_object *object,
bool no_space_allocated_yet)
{
struct cachefiles_cache *cache = object->volume->cache;
+ struct fscache_cookie *cookie = object->cookie;
loff_t start = *_start, pos;
size_t len = *_len, down;
int ret;
@@ -526,6 +529,9 @@ int __cachefiles_prepare_write(struct cachefiles_object *object,
if (no_space_allocated_yet)
goto check_space;

+ if (test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags))
+ goto check_space;
+
pos = cachefiles_inject_read_error();
if (pos == 0)
pos = vfs_llseek(file, *_start, SEEK_DATA);
diff --git a/fs/cachefiles/ondemand.c b/fs/cachefiles/ondemand.c
index 1fee702d5529..a317857e2dfd 100644
--- a/fs/cachefiles/ondemand.c
+++ b/fs/cachefiles/ondemand.c
@@ -166,12 +166,9 @@ int cachefiles_ondemand_copen(struct cachefiles_cache *cache, char *args)

cookie = req->object->cookie;
cookie->object_size = size;
- if (size)
- clear_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
- else
+ if (size == 0)
set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
trace_cachefiles_ondemand_copen(req->object, id, size);
-
out:
complete(&req->done);
return ret;
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index 74920826d8f6..49c269c078eb 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -340,7 +340,7 @@ static struct fscache_cookie *fscache_alloc_cookie(
cookie->key_len = index_key_len;
cookie->aux_len = aux_data_len;
cookie->object_size = object_size;
- if (object_size == 0)
+ if (object_size == 0 && !(advice & FSCACHE_ADV_WANT_CACHE_SIZE))
__set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);

if (fscache_set_key(cookie, index_key, index_key_len) < 0)
--
2.27.0