Skip to content

Commit 16f2f4e

Browse files
committed
nfs: Implement cache I/O by accessing the cache directly
Move NFS to using fscache DIO API instead of the old upstream I/O API as that has been removed. This is a stopgap solution as the intention is that at sometime in the future, the cache will move to using larger blocks and won't be able to store individual pages in order to deal with the potential for data corruption due to the backing filesystem being able insert/remove bridging blocks of zeros into its extent list[1]. NFS then reads and writes cache pages synchronously and one page at a time. The preferred change would be to use the netfs lib, but the new I/O API can be used directly. It's just that as the cache now needs to track data for itself, caching blocks may exceed page size... This code is somewhat borrowed from my "fallback I/O" patchset[2]. Changes ======= ver #3: - Restore lost =n fallback for nfs_fscache_release_page()[2]. Signed-off-by: David Howells <[email protected]> Tested-by: Dave Wysochanski <[email protected]> Acked-by: Jeff Layton <[email protected]> cc: Trond Myklebust <[email protected]> cc: Anna Schumaker <[email protected]> cc: [email protected] cc: [email protected] Link: https://lore.kernel.org/r/[email protected] [1] Link: https://lore.kernel.org/r/[email protected]/ [2] Link: https://lore.kernel.org/r/163189108292.2509237.12615909591150927232.stgit@warthog.procyon.org.uk/ [2] Link: https://lore.kernel.org/r/163906981318.143852.17220018647843475985.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967184451.1823006.6450645559828329590.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021577632.640689.11069627070150063812.stgit@warthog.procyon.org.uk/ # v4
1 parent a6b5a28 commit 16f2f4e

File tree

6 files changed

+163
-83
lines changed

6 files changed

+163
-83
lines changed

fs/fscache/io.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ int __fscache_begin_read_operation(struct netfs_cache_resources *cres,
150150
}
151151
EXPORT_SYMBOL(__fscache_begin_read_operation);
152152

153+
int __fscache_begin_write_operation(struct netfs_cache_resources *cres,
154+
struct fscache_cookie *cookie)
155+
{
156+
return fscache_begin_operation(cres, cookie, FSCACHE_WANT_PARAMS,
157+
fscache_access_io_write);
158+
}
159+
EXPORT_SYMBOL(__fscache_begin_write_operation);
160+
153161
/**
154162
* fscache_set_page_dirty - Mark page dirty and pin a cache object for writeback
155163
* @page: The page being dirtied

fs/nfs/fscache.c

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -249,48 +249,128 @@ void nfs_fscache_release_file(struct inode *inode, struct file *filp)
249249
}
250250
}
251251

252+
static inline void fscache_end_operation(struct netfs_cache_resources *cres)
253+
{
254+
const struct netfs_cache_ops *ops = fscache_operation_valid(cres);
255+
256+
if (ops)
257+
ops->end_operation(cres);
258+
}
259+
260+
/*
261+
* Fallback page reading interface.
262+
*/
263+
static int fscache_fallback_read_page(struct inode *inode, struct page *page)
264+
{
265+
struct netfs_cache_resources cres;
266+
struct fscache_cookie *cookie = nfs_i_fscache(inode);
267+
struct iov_iter iter;
268+
struct bio_vec bvec[1];
269+
int ret;
270+
271+
memset(&cres, 0, sizeof(cres));
272+
bvec[0].bv_page = page;
273+
bvec[0].bv_offset = 0;
274+
bvec[0].bv_len = PAGE_SIZE;
275+
iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
276+
277+
ret = fscache_begin_read_operation(&cres, cookie);
278+
if (ret < 0)
279+
return ret;
280+
281+
ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
282+
NULL, NULL);
283+
fscache_end_operation(&cres);
284+
return ret;
285+
}
286+
287+
/*
288+
* Fallback page writing interface.
289+
*/
290+
static int fscache_fallback_write_page(struct inode *inode, struct page *page,
291+
bool no_space_allocated_yet)
292+
{
293+
struct netfs_cache_resources cres;
294+
struct fscache_cookie *cookie = nfs_i_fscache(inode);
295+
struct iov_iter iter;
296+
struct bio_vec bvec[1];
297+
loff_t start = page_offset(page);
298+
size_t len = PAGE_SIZE;
299+
int ret;
300+
301+
memset(&cres, 0, sizeof(cres));
302+
bvec[0].bv_page = page;
303+
bvec[0].bv_offset = 0;
304+
bvec[0].bv_len = PAGE_SIZE;
305+
iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
306+
307+
ret = fscache_begin_write_operation(&cres, cookie);
308+
if (ret < 0)
309+
return ret;
310+
311+
ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
312+
no_space_allocated_yet);
313+
if (ret == 0)
314+
ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
315+
fscache_end_operation(&cres);
316+
return ret;
317+
}
318+
252319
/*
253320
* Retrieve a page from fscache
254321
*/
255-
int __nfs_readpage_from_fscache(struct nfs_open_context *ctx,
256-
struct inode *inode, struct page *page)
322+
int __nfs_readpage_from_fscache(struct inode *inode, struct page *page)
257323
{
324+
int ret;
325+
258326
dfprintk(FSCACHE,
259327
"NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
260328
nfs_i_fscache(inode), page, page->index, page->flags, inode);
261329

262330
if (PageChecked(page)) {
331+
dfprintk(FSCACHE, "NFS: readpage_from_fscache: PageChecked\n");
263332
ClearPageChecked(page);
264333
return 1;
265334
}
266335

267-
return -ENOBUFS; // TODO: Use netfslib
268-
}
269-
270-
/*
271-
* Retrieve a set of pages from fscache
272-
*/
273-
int __nfs_readpages_from_fscache(struct nfs_open_context *ctx,
274-
struct inode *inode,
275-
struct address_space *mapping,
276-
struct list_head *pages,
277-
unsigned *nr_pages)
278-
{
279-
dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n",
280-
nfs_i_fscache(inode), *nr_pages, inode);
336+
ret = fscache_fallback_read_page(inode, page);
337+
if (ret < 0) {
338+
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
339+
dfprintk(FSCACHE,
340+
"NFS: readpage_from_fscache failed %d\n", ret);
341+
SetPageChecked(page);
342+
return ret;
343+
}
281344

282-
return -ENOBUFS; // TODO: Use netfslib
345+
/* Read completed synchronously */
346+
dfprintk(FSCACHE, "NFS: readpage_from_fscache: read successful\n");
347+
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK);
348+
SetPageUptodate(page);
349+
return 0;
283350
}
284351

285352
/*
286-
* Store a newly fetched page in fscache
287-
* - PG_fscache must be set on the page
353+
* Store a newly fetched page in fscache. We can be certain there's no page
354+
* stored in the cache as yet otherwise we would've read it from there.
288355
*/
289-
void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
356+
void __nfs_readpage_to_fscache(struct inode *inode, struct page *page)
290357
{
358+
int ret;
359+
291360
dfprintk(FSCACHE,
292-
"NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n",
293-
nfs_i_fscache(inode), page, page->index, page->flags, sync);
361+
"NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx))\n",
362+
nfs_i_fscache(inode), page, page->index, page->flags);
294363

295-
return; // TODO: Use netfslib
364+
ret = fscache_fallback_write_page(inode, page, true);
365+
366+
dfprintk(FSCACHE,
367+
"NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n",
368+
page, page->index, page->flags, ret);
369+
370+
if (ret != 0) {
371+
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL);
372+
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED);
373+
} else {
374+
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK);
375+
}
296376
}

fs/nfs/fscache.h

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,10 @@ extern void nfs_fscache_clear_inode(struct inode *);
4444
extern void nfs_fscache_open_file(struct inode *, struct file *);
4545
extern void nfs_fscache_release_file(struct inode *, struct file *);
4646

47-
extern void __nfs_fscache_invalidate_page(struct page *, struct inode *);
48-
49-
extern int __nfs_readpage_from_fscache(struct nfs_open_context *,
50-
struct inode *, struct page *);
51-
extern int __nfs_readpages_from_fscache(struct nfs_open_context *,
52-
struct inode *, struct address_space *,
53-
struct list_head *, unsigned *);
54-
extern void __nfs_readpage_to_fscache(struct inode *, struct page *, int);
47+
extern int __nfs_readpage_from_fscache(struct inode *, struct page *);
48+
extern void __nfs_read_completion_to_fscache(struct nfs_pgio_header *hdr,
49+
unsigned long bytes);
50+
extern void __nfs_readpage_to_fscache(struct inode *, struct page *);
5551

5652
static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
5753
{
@@ -69,27 +65,11 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
6965
/*
7066
* Retrieve a page from an inode data storage object.
7167
*/
72-
static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
73-
struct inode *inode,
68+
static inline int nfs_readpage_from_fscache(struct inode *inode,
7469
struct page *page)
7570
{
7671
if (NFS_I(inode)->fscache)
77-
return __nfs_readpage_from_fscache(ctx, inode, page);
78-
return -ENOBUFS;
79-
}
80-
81-
/*
82-
* Retrieve a set of pages from an inode data storage object.
83-
*/
84-
static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
85-
struct inode *inode,
86-
struct address_space *mapping,
87-
struct list_head *pages,
88-
unsigned *nr_pages)
89-
{
90-
if (NFS_I(inode)->fscache)
91-
return __nfs_readpages_from_fscache(ctx, inode, mapping, pages,
92-
nr_pages);
72+
return __nfs_readpage_from_fscache(inode, page);
9373
return -ENOBUFS;
9474
}
9575

@@ -98,11 +78,10 @@ static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
9878
* in the cache.
9979
*/
10080
static inline void nfs_readpage_to_fscache(struct inode *inode,
101-
struct page *page,
102-
int sync)
81+
struct page *page)
10382
{
104-
if (PageFsCache(page))
105-
__nfs_readpage_to_fscache(inode, page, sync);
83+
if (NFS_I(inode)->fscache)
84+
__nfs_readpage_to_fscache(inode, page);
10685
}
10786

10887
static inline void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata,
@@ -156,22 +135,13 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
156135
{
157136
return 1; /* True: may release page */
158137
}
159-
static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
160-
struct inode *inode,
138+
static inline int nfs_readpage_from_fscache(struct inode *inode,
161139
struct page *page)
162140
{
163141
return -ENOBUFS;
164142
}
165-
static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
166-
struct inode *inode,
167-
struct address_space *mapping,
168-
struct list_head *pages,
169-
unsigned *nr_pages)
170-
{
171-
return -ENOBUFS;
172-
}
173143
static inline void nfs_readpage_to_fscache(struct inode *inode,
174-
struct page *page, int sync) {}
144+
struct page *page) {}
175145

176146

177147
static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {}

fs/nfs/read.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ static void nfs_readpage_release(struct nfs_page *req, int error)
123123
struct address_space *mapping = page_file_mapping(page);
124124

125125
if (PageUptodate(page))
126-
nfs_readpage_to_fscache(inode, page, 0);
126+
nfs_readpage_to_fscache(inode, page);
127127
else if (!PageError(page) && !PagePrivate(page))
128128
generic_error_remove_page(mapping, page);
129129
unlock_page(page);
@@ -305,6 +305,12 @@ readpage_async_filler(void *data, struct page *page)
305305

306306
aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE);
307307

308+
if (!IS_SYNC(page->mapping->host)) {
309+
error = nfs_readpage_from_fscache(page->mapping->host, page);
310+
if (error == 0)
311+
goto out_unlock;
312+
}
313+
308314
new = nfs_create_request(desc->ctx, page, 0, aligned_len);
309315
if (IS_ERR(new))
310316
goto out_error;
@@ -320,6 +326,7 @@ readpage_async_filler(void *data, struct page *page)
320326
return 0;
321327
out_error:
322328
error = PTR_ERR(new);
329+
out_unlock:
323330
unlock_page(page);
324331
out:
325332
return error;
@@ -366,12 +373,6 @@ int nfs_readpage(struct file *file, struct page *page)
366373
desc.ctx = get_nfs_open_context(nfs_file_open_context(file));
367374

368375
xchg(&desc.ctx->error, 0);
369-
if (!IS_SYNC(inode)) {
370-
ret = nfs_readpage_from_fscache(desc.ctx, inode, page);
371-
if (ret == 0)
372-
goto out_wait;
373-
}
374-
375376
nfs_pageio_init_read(&desc.pgio, inode, false,
376377
&nfs_async_read_completion_ops);
377378

@@ -381,7 +382,6 @@ int nfs_readpage(struct file *file, struct page *page)
381382

382383
nfs_pageio_complete_read(&desc.pgio);
383384
ret = desc.pgio.pg_error < 0 ? desc.pgio.pg_error : 0;
384-
out_wait:
385385
if (!ret) {
386386
ret = wait_on_page_locked_killable(page);
387387
if (!PageUptodate(page) && !ret)
@@ -419,22 +419,13 @@ int nfs_readpages(struct file *file, struct address_space *mapping,
419419
} else
420420
desc.ctx = get_nfs_open_context(nfs_file_open_context(file));
421421

422-
/* attempt to read as many of the pages as possible from the cache
423-
* - this returns -ENOBUFS immediately if the cookie is negative
424-
*/
425-
ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping,
426-
pages, &nr_pages);
427-
if (ret == 0)
428-
goto read_complete; /* all pages were read */
429-
430422
nfs_pageio_init_read(&desc.pgio, inode, false,
431423
&nfs_async_read_completion_ops);
432424

433425
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
434426

435427
nfs_pageio_complete_read(&desc.pgio);
436428

437-
read_complete:
438429
put_nfs_open_context(desc.ctx);
439430
out:
440431
trace_nfs_aop_readahead_done(inode, nr_pages, ret);

fs/nfs/write.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,8 +2126,11 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
21262126
if (PagePrivate(page))
21272127
return -EBUSY;
21282128

2129-
if (!nfs_fscache_release_page(page, GFP_KERNEL))
2130-
return -EBUSY;
2129+
if (PageFsCache(page)) {
2130+
if (mode == MIGRATE_ASYNC)
2131+
return -EBUSY;
2132+
wait_on_page_fscache(page);
2133+
}
21312134

21322135
return migrate_page(mapping, newpage, page, mode);
21332136
}

include/linux/fscache.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool);
168168
extern void __fscache_resize_cookie(struct fscache_cookie *, loff_t);
169169
extern void __fscache_invalidate(struct fscache_cookie *, const void *, loff_t, unsigned int);
170170
extern int __fscache_begin_read_operation(struct netfs_cache_resources *, struct fscache_cookie *);
171+
extern int __fscache_begin_write_operation(struct netfs_cache_resources *, struct fscache_cookie *);
171172

172173
extern void __fscache_write_to_cache(struct fscache_cookie *, struct address_space *,
173174
loff_t, size_t, loff_t, netfs_io_terminated_t, void *,
@@ -499,6 +500,33 @@ int fscache_read(struct netfs_cache_resources *cres,
499500
term_func, term_func_priv);
500501
}
501502

503+
/**
504+
* fscache_begin_write_operation - Begin a write operation for the netfs lib
505+
* @cres: The cache resources for the write being performed
506+
* @cookie: The cookie representing the cache object
507+
*
508+
* Begin a write operation on behalf of the netfs helper library. @cres
509+
* indicates the cache resources to which the operation state should be
510+
* attached; @cookie indicates the cache object that will be accessed.
511+
*
512+
* @cres->inval_counter is set from @cookie->inval_counter for comparison at
513+
* the end of the operation. This allows invalidation during the operation to
514+
* be detected by the caller.
515+
*
516+
* Returns:
517+
* * 0 - Success
518+
* * -ENOBUFS - No caching available
519+
* * Other error code from the cache, such as -ENOMEM.
520+
*/
521+
static inline
522+
int fscache_begin_write_operation(struct netfs_cache_resources *cres,
523+
struct fscache_cookie *cookie)
524+
{
525+
if (fscache_cookie_enabled(cookie))
526+
return __fscache_begin_write_operation(cres, cookie);
527+
return -ENOBUFS;
528+
}
529+
502530
/**
503531
* fscache_write - Start a write to the cache.
504532
* @cres: The cache resources to use

0 commit comments

Comments
 (0)