Skip to content

Commit

Permalink
fscache: Implement a fallback I/O interface to replace the old API
Browse files Browse the repository at this point in the history
Implement an alternative to using the netfslib-base I/O API so that we can
move forwards on getting rid of the old API.  Note that this API is should
not be used by new filesystems as it still uses the backing filesystem to
track unfilled holes in the backing file, though using SEEK_DATA/SEEK_HOLE
rather than bmap().

This is dangerous and can lead to corrupted data as the backing filesystem
cannot be relied on not to fill in holes with blocks of zeros in order to
optimise an extent list[1].  It may also punch out blocks of zeros to
create holes for the same reason, but this is less of a problem.

Also adjust the macros that must be defined to indicate which API is to be
used:

 (*) FSCACHE_USE_OLD_IO_API - Use the current upstream API.  This will be
     deleted.

 (*) FSCACHE_USE_FALLBACK_IO_API - Use the API added here.

 (*) FSCACHE_USE_NEW_IO_API - Use the new API or netfs API.

Changes
=======
ver #2:
  - Changed "deprecated" to "fallback" in the new function names[2].
  - Need to define FSCACHE_USE_FALLBACK_IO_API in fscache/io.c to enable
    the prototypes of the functions[3].
  - Removed a couple of unused variables[3].
  - Make netfs/read_helpers.c use NETFS_READ_HOLE_*.

Signed-off-by: David Howells <[email protected]>
Tested-by: Dave Wysochanski <[email protected]>
cc: [email protected]
Link: https://lore.kernel.org/r/[email protected]/ [1]
Link: https://lore.kernel.org/r/CAHk-=wiVK+1CyEjW8u71zVPK8msea=qPpznX35gnX+s8sXnJTg@mail.gmail.com/ [2]
Link: https://lore.kernel.org/r/[email protected]/ [3]
Link: https://lore.kernel.org/r/163162770137.438332.13788466444753625553.stgit@warthog.procyon.org.uk/ # rfc
Link: https://lore.kernel.org/r/163189107352.2509237.759630157032861275.stgit@warthog.procyon.org.uk/ # rfc v2
  • Loading branch information
dhowells committed Sep 21, 2021
1 parent 9f759b1 commit d9174eb
Show file tree
Hide file tree
Showing 11 changed files with 314 additions and 37 deletions.
1 change: 1 addition & 0 deletions fs/9p/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifndef _9P_CACHE_H
#define _9P_CACHE_H
#ifdef CONFIG_9P_FSCACHE
#define FSCACHE_USE_OLD_IO_API
#include <linux/fscache.h>
#include <linux/spinlock.h>

Expand Down
28 changes: 25 additions & 3 deletions fs/cachefiles/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ static void cachefiles_read_complete(struct kiocb *iocb, long ret, long ret2)
static int cachefiles_read(struct netfs_cache_resources *cres,
loff_t start_pos,
struct iov_iter *iter,
bool seek_data,
enum netfs_read_from_hole read_hole,
netfs_io_terminated_t term_func,
void *term_func_priv)
{
struct cachefiles_kiocb *ki;
struct file *file = cres->cache_priv2;
unsigned int old_nofs;
ssize_t ret = -ENOBUFS;
ssize_t ret = -ENODATA;
size_t len = iov_iter_count(iter), skipped = 0;

_enter("%pD,%li,%llx,%zx/%llx",
Expand All @@ -75,7 +75,7 @@ static int cachefiles_read(struct netfs_cache_resources *cres,
/* If the caller asked us to seek for data before doing the read, then
* we should do that now. If we find a gap, we fill it with zeros.
*/
if (seek_data) {
if (read_hole != NETFS_READ_HOLE_IGNORE) {
loff_t off = start_pos, off2;

off2 = vfs_llseek(file, off, SEEK_DATA);
Expand All @@ -90,6 +90,9 @@ static int cachefiles_read(struct netfs_cache_resources *cres,
* in the region, so clear the rest of the buffer and
* return success.
*/
if (read_hole == NETFS_READ_HOLE_FAIL)
goto presubmission_error;

iov_iter_zero(len, iter);
skipped = len;
ret = 0;
Expand Down Expand Up @@ -345,6 +348,24 @@ static int cachefiles_prepare_write(struct netfs_cache_resources *cres,
return 0;
}

/*
* Prepare for a write to occur from the fallback I/O API.
*/
static int cachefiles_prepare_fallback_write(struct netfs_cache_resources *cres,
pgoff_t index)
{
struct fscache_operation *op = cres->cache_priv;
struct cachefiles_object *object;
struct cachefiles_cache *cache;

_enter("%lx", index);

object = container_of(op->object, struct cachefiles_object, fscache);
cache = container_of(object->fscache.cache,
struct cachefiles_cache, cache);
return cachefiles_has_space(cache, 0, 1);
}

/*
* Clean up an operation.
*/
Expand All @@ -371,6 +392,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
.write = cachefiles_write,
.prepare_read = cachefiles_prepare_read,
.prepare_write = cachefiles_prepare_write,
.prepare_fallback_write = cachefiles_prepare_fallback_write,
};

/*
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/fscache.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef _CIFS_FSCACHE_H
#define _CIFS_FSCACHE_H

#define FSCACHE_USE_OLD_IO_API
#include <linux/fscache.h>

#include "cifsglob.h"
Expand Down
3 changes: 3 additions & 0 deletions fs/fscache/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,15 @@ extern atomic_t fscache_n_stores;
extern atomic_t fscache_n_stores_ok;
extern atomic_t fscache_n_stores_again;
extern atomic_t fscache_n_stores_nobufs;
extern atomic_t fscache_n_stores_intr;
extern atomic_t fscache_n_stores_oom;
extern atomic_t fscache_n_store_ops;
extern atomic_t fscache_n_store_calls;
extern atomic_t fscache_n_store_pages;
extern atomic_t fscache_n_store_radix_deletes;
extern atomic_t fscache_n_store_pages_over_limit;
extern atomic_t fscache_n_stores_object_dead;
extern atomic_t fscache_n_store_op_waits;

extern atomic_t fscache_n_store_vmscan_not_storing;
extern atomic_t fscache_n_store_vmscan_gone;
Expand Down
137 changes: 119 additions & 18 deletions fs/fscache/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
#define FSCACHE_DEBUG_LEVEL PAGE
#include <linux/module.h>
#define FSCACHE_USE_NEW_IO_API
#define FSCACHE_USE_FALLBACK_IO_API
#include <linux/fscache-cache.h>
#include <linux/uio.h>
#include <linux/bvec.h>
#include <linux/slab.h>
#include <linux/netfs.h>
#include "internal.h"
Expand All @@ -35,7 +38,10 @@ int __fscache_begin_operation(struct netfs_cache_resources *cres,

_enter("c=%08x", cres->debug_id);

fscache_stat(&fscache_n_retrievals);
if (for_write)
fscache_stat(&fscache_n_stores);
else
fscache_stat(&fscache_n_retrievals);

if (hlist_empty(&cookie->backing_objects))
goto nobufs;
Expand Down Expand Up @@ -77,31 +83,51 @@ int __fscache_begin_operation(struct netfs_cache_resources *cres,
goto nobufs_unlock_dec;
spin_unlock(&cookie->lock);

fscache_stat(&fscache_n_retrieval_ops);

/* we wait for the operation to become active, and then process it
* *here*, in this thread, and not in the thread pool */
ret = fscache_wait_for_operation_activation(
object, op,
__fscache_stat(&fscache_n_retrieval_op_waits),
__fscache_stat(&fscache_n_retrievals_object_dead));
if (for_write) {
fscache_stat(&fscache_n_store_ops);

ret = fscache_wait_for_operation_activation(
object, op,
__fscache_stat(&fscache_n_store_op_waits),
__fscache_stat(&fscache_n_stores_object_dead));
} else {
fscache_stat(&fscache_n_retrieval_ops);

ret = fscache_wait_for_operation_activation(
object, op,
__fscache_stat(&fscache_n_retrieval_op_waits),
__fscache_stat(&fscache_n_retrievals_object_dead));
}
if (ret < 0)
goto error;

/* ask the cache to honour the operation */
ret = object->cache->ops->begin_operation(cres, op);

error:
if (ret == -ENOMEM)
fscache_stat(&fscache_n_retrievals_nomem);
else if (ret == -ERESTARTSYS)
fscache_stat(&fscache_n_retrievals_intr);
else if (ret == -ENODATA)
fscache_stat(&fscache_n_retrievals_nodata);
else if (ret < 0)
fscache_stat(&fscache_n_retrievals_nobufs);
else
fscache_stat(&fscache_n_retrievals_ok);
if (for_write) {
if (ret == -ENOMEM)
fscache_stat(&fscache_n_stores_oom);
else if (ret == -ERESTARTSYS)
fscache_stat(&fscache_n_stores_intr);
else if (ret < 0)
fscache_stat(&fscache_n_stores_nobufs);
else
fscache_stat(&fscache_n_stores_ok);
} else {
if (ret == -ENOMEM)
fscache_stat(&fscache_n_retrievals_nomem);
else if (ret == -ERESTARTSYS)
fscache_stat(&fscache_n_retrievals_intr);
else if (ret == -ENODATA)
fscache_stat(&fscache_n_retrievals_nodata);
else if (ret < 0)
fscache_stat(&fscache_n_retrievals_nobufs);
else
fscache_stat(&fscache_n_retrievals_ok);
}

fscache_put_operation(op);
_leave(" = %d", ret);
Expand All @@ -116,8 +142,83 @@ int __fscache_begin_operation(struct netfs_cache_resources *cres,
if (wake_cookie)
__fscache_wake_unused_cookie(cookie);
nobufs:
fscache_stat(&fscache_n_retrievals_nobufs);
if (for_write)
fscache_stat(&fscache_n_stores_nobufs);
else
fscache_stat(&fscache_n_retrievals_nobufs);
_leave(" = -ENOBUFS");
return -ENOBUFS;
}
EXPORT_SYMBOL(__fscache_begin_operation);

/*
* Clean up an operation.
*/
static void fscache_end_operation(struct netfs_cache_resources *cres)
{
cres->ops->end_operation(cres);
}

/*
* Fallback page reading interface.
*/
int __fscache_fallback_read_page(struct fscache_cookie *cookie, struct page *page)
{
struct netfs_cache_resources cres;
struct iov_iter iter;
struct bio_vec bvec[1];
int ret;

_enter("%lx", page->index);

memset(&cres, 0, sizeof(cres));
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);

ret = fscache_begin_read_operation(&cres, cookie);
if (ret < 0)
return ret;

ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
NULL, NULL);
fscache_end_operation(&cres);
_leave(" = %d", ret);
return ret;
}
EXPORT_SYMBOL(__fscache_fallback_read_page);

/*
* Fallback page writing interface.
*/
int __fscache_fallback_write_page(struct fscache_cookie *cookie, struct page *page)
{
struct netfs_cache_resources cres;
struct iov_iter iter;
struct bio_vec bvec[1];
int ret;

_enter("%lx", page->index);

memset(&cres, 0, sizeof(cres));
bvec[0].bv_page = page;
bvec[0].bv_offset = 0;
bvec[0].bv_len = PAGE_SIZE;
iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);

ret = __fscache_begin_operation(&cres, cookie, true);
if (ret < 0)
return ret;

ret = cres.ops->prepare_fallback_write(&cres, page_index(page));
if (ret < 0)
goto out;

ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
out:
fscache_end_operation(&cres);
_leave(" = %d", ret);
return ret;
}
EXPORT_SYMBOL(__fscache_fallback_write_page);
1 change: 1 addition & 0 deletions fs/fscache/page.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#define FSCACHE_DEBUG_LEVEL PAGE
#include <linux/module.h>
#define FSCACHE_USE_OLD_IO_API
#include <linux/fscache-cache.h>
#include <linux/buffer_head.h>
#include <linux/pagevec.h>
Expand Down
12 changes: 9 additions & 3 deletions fs/fscache/stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,15 @@ atomic_t fscache_n_stores;
atomic_t fscache_n_stores_ok;
atomic_t fscache_n_stores_again;
atomic_t fscache_n_stores_nobufs;
atomic_t fscache_n_stores_intr;
atomic_t fscache_n_stores_oom;
atomic_t fscache_n_store_ops;
atomic_t fscache_n_store_calls;
atomic_t fscache_n_store_pages;
atomic_t fscache_n_store_radix_deletes;
atomic_t fscache_n_store_pages_over_limit;
atomic_t fscache_n_stores_object_dead;
atomic_t fscache_n_store_op_waits;

atomic_t fscache_n_store_vmscan_not_storing;
atomic_t fscache_n_store_vmscan_gone;
Expand Down Expand Up @@ -221,18 +224,21 @@ int fscache_stats_show(struct seq_file *m, void *v)
atomic_read(&fscache_n_retrieval_op_waits),
atomic_read(&fscache_n_retrievals_object_dead));

seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n",
seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u int=%u oom=%u\n",
atomic_read(&fscache_n_stores),
atomic_read(&fscache_n_stores_ok),
atomic_read(&fscache_n_stores_again),
atomic_read(&fscache_n_stores_nobufs),
atomic_read(&fscache_n_stores_intr),
atomic_read(&fscache_n_stores_oom));
seq_printf(m, "Stores : ops=%u run=%u pgs=%u rxd=%u olm=%u\n",
seq_printf(m, "Stores : ops=%u owt=%u run=%u pgs=%u rxd=%u olm=%u abt=%u\n",
atomic_read(&fscache_n_store_ops),
atomic_read(&fscache_n_store_op_waits),
atomic_read(&fscache_n_store_calls),
atomic_read(&fscache_n_store_pages),
atomic_read(&fscache_n_store_radix_deletes),
atomic_read(&fscache_n_store_pages_over_limit));
atomic_read(&fscache_n_store_pages_over_limit),
atomic_read(&fscache_n_stores_object_dead));

seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u wt=%u\n",
atomic_read(&fscache_n_store_vmscan_not_storing),
Expand Down
8 changes: 4 additions & 4 deletions fs/netfs/read_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ static void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error
*/
static void netfs_read_from_cache(struct netfs_read_request *rreq,
struct netfs_read_subrequest *subreq,
bool seek_data)
enum netfs_read_from_hole read_hole)
{
struct netfs_cache_resources *cres = &rreq->cache_resources;
struct iov_iter iter;
Expand All @@ -180,7 +180,7 @@ static void netfs_read_from_cache(struct netfs_read_request *rreq,
subreq->start + subreq->transferred,
subreq->len - subreq->transferred);

cres->ops->read(cres, subreq->start, &iter, seek_data,
cres->ops->read(cres, subreq->start, &iter, read_hole,
netfs_cache_read_terminated, subreq);
}

Expand Down Expand Up @@ -468,7 +468,7 @@ static void netfs_rreq_short_read(struct netfs_read_request *rreq,
netfs_get_read_subrequest(subreq);
atomic_inc(&rreq->nr_rd_ops);
if (subreq->source == NETFS_READ_FROM_CACHE)
netfs_read_from_cache(rreq, subreq, true);
netfs_read_from_cache(rreq, subreq, NETFS_READ_HOLE_CLEAR);
else
netfs_read_from_server(rreq, subreq);
}
Expand Down Expand Up @@ -796,7 +796,7 @@ static bool netfs_rreq_submit_slice(struct netfs_read_request *rreq,
netfs_read_from_server(rreq, subreq);
break;
case NETFS_READ_FROM_CACHE:
netfs_read_from_cache(rreq, subreq, false);
netfs_read_from_cache(rreq, subreq, NETFS_READ_HOLE_IGNORE);
break;
default:
BUG();
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/fscache.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#define FSCACHE_USE_OLD_IO_API
#include <linux/fscache.h>

#ifdef CONFIG_NFS_FSCACHE
Expand Down
Loading

0 comments on commit d9174eb

Please sign in to comment.