Skip to content

Commit 0174ee9

Browse files
dhowellssmfrench
authored andcommitted
cifs: Implement cache I/O by accessing the cache directly
Move cifs 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]. cifs 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]. Signed-off-by: David Howells <[email protected]> cc: Steve French <[email protected]> cc: Shyam Prasad N <[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] Acked-by: Jeff Layton <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent bee9f65 commit 0174ee9

File tree

3 files changed

+207
-53
lines changed

3 files changed

+207
-53
lines changed

fs/cifs/file.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4276,12 +4276,12 @@ cifs_readv_complete(struct work_struct *work)
42764276
} else
42774277
SetPageError(page);
42784278

4279-
unlock_page(page);
4280-
42814279
if (rdata->result == 0 ||
42824280
(rdata->result == -EAGAIN && got_bytes))
42834281
cifs_readpage_to_fscache(rdata->mapping->host, page);
42844282

4283+
unlock_page(page);
4284+
42854285
got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
42864286

42874287
put_page(page);
@@ -4396,7 +4396,11 @@ static void cifs_readahead(struct readahead_control *ractl)
43964396
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(ractl->file);
43974397
struct TCP_Server_Info *server;
43984398
pid_t pid;
4399-
unsigned int xid, last_batch_size = 0;
4399+
unsigned int xid, nr_pages, last_batch_size = 0, cache_nr_pages = 0;
4400+
pgoff_t next_cached = ULONG_MAX;
4401+
bool caching = fscache_cookie_enabled(cifs_inode_cookie(ractl->mapping->host)) &&
4402+
cifs_inode_cookie(ractl->mapping->host)->cache_priv;
4403+
bool check_cache = caching;
44004404

44014405
xid = get_xid();
44024406

@@ -4414,12 +4418,52 @@ static void cifs_readahead(struct readahead_control *ractl)
44144418
/*
44154419
* Chop the readahead request up into rsize-sized read requests.
44164420
*/
4417-
while (readahead_count(ractl) - last_batch_size) {
4418-
unsigned int i, nr_pages, got, rsize;
4421+
while ((nr_pages = readahead_count(ractl) - last_batch_size)) {
4422+
unsigned int i, got, rsize;
44194423
struct page *page;
44204424
struct cifs_readdata *rdata;
44214425
struct cifs_credits credits_on_stack;
44224426
struct cifs_credits *credits = &credits_on_stack;
4427+
pgoff_t index = readahead_index(ractl) + last_batch_size;
4428+
4429+
/*
4430+
* Find out if we have anything cached in the range of
4431+
* interest, and if so, where the next chunk of cached data is.
4432+
*/
4433+
if (caching) {
4434+
if (check_cache) {
4435+
rc = cifs_fscache_query_occupancy(
4436+
ractl->mapping->host, index, nr_pages,
4437+
&next_cached, &cache_nr_pages);
4438+
if (rc < 0)
4439+
caching = false;
4440+
check_cache = false;
4441+
}
4442+
4443+
if (index == next_cached) {
4444+
/*
4445+
* TODO: Send a whole batch of pages to be read
4446+
* by the cache.
4447+
*/
4448+
page = readahead_page(ractl);
4449+
4450+
if (cifs_readpage_from_fscache(ractl->mapping->host,
4451+
page) < 0) {
4452+
/*
4453+
* TODO: Deal with cache read failure
4454+
* here, but for the moment, delegate
4455+
* that to readpage.
4456+
*/
4457+
caching = false;
4458+
}
4459+
unlock_page(page);
4460+
next_cached++;
4461+
cache_nr_pages--;
4462+
if (cache_nr_pages == 0)
4463+
check_cache = true;
4464+
continue;
4465+
}
4466+
}
44234467

44244468
if (open_file->invalidHandle) {
44254469
rc = cifs_reopen_file(open_file, true);
@@ -4435,6 +4479,7 @@ static void cifs_readahead(struct readahead_control *ractl)
44354479
if (rc)
44364480
break;
44374481
nr_pages = min_t(size_t, rsize / PAGE_SIZE, readahead_count(ractl));
4482+
nr_pages = min_t(size_t, nr_pages, next_cached - index);
44384483

44394484
/*
44404485
* Give up immediately if rsize is too small to read an entire

fs/cifs/fscache.c

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,37 +134,127 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
134134
}
135135
}
136136

137+
static inline void fscache_end_operation(struct netfs_cache_resources *cres)
138+
{
139+
const struct netfs_cache_ops *ops = fscache_operation_valid(cres);
140+
141+
if (ops)
142+
ops->end_operation(cres);
143+
}
144+
137145
/*
138-
* Retrieve a page from FS-Cache
146+
* Fallback page reading interface.
139147
*/
140-
int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
148+
static int fscache_fallback_read_page(struct inode *inode, struct page *page)
141149
{
142-
cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
143-
__func__, CIFS_I(inode)->fscache, page, inode);
144-
return -ENOBUFS; // Needs conversion to using netfslib
150+
struct netfs_cache_resources cres;
151+
struct fscache_cookie *cookie = cifs_inode_cookie(inode);
152+
struct iov_iter iter;
153+
struct bio_vec bvec[1];
154+
int ret;
155+
156+
memset(&cres, 0, sizeof(cres));
157+
bvec[0].bv_page = page;
158+
bvec[0].bv_offset = 0;
159+
bvec[0].bv_len = PAGE_SIZE;
160+
iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
161+
162+
ret = fscache_begin_read_operation(&cres, cookie);
163+
if (ret < 0)
164+
return ret;
165+
166+
ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
167+
NULL, NULL);
168+
fscache_end_operation(&cres);
169+
return ret;
145170
}
146171

147172
/*
148-
* Retrieve a set of pages from FS-Cache
173+
* Fallback page writing interface.
149174
*/
150-
int __cifs_readpages_from_fscache(struct inode *inode,
151-
struct address_space *mapping,
152-
struct list_head *pages,
153-
unsigned *nr_pages)
175+
static int fscache_fallback_write_page(struct inode *inode, struct page *page,
176+
bool no_space_allocated_yet)
154177
{
155-
cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
156-
__func__, CIFS_I(inode)->fscache, *nr_pages, inode);
157-
return -ENOBUFS; // Needs conversion to using netfslib
178+
struct netfs_cache_resources cres;
179+
struct fscache_cookie *cookie = cifs_inode_cookie(inode);
180+
struct iov_iter iter;
181+
struct bio_vec bvec[1];
182+
loff_t start = page_offset(page);
183+
size_t len = PAGE_SIZE;
184+
int ret;
185+
186+
memset(&cres, 0, sizeof(cres));
187+
bvec[0].bv_page = page;
188+
bvec[0].bv_offset = 0;
189+
bvec[0].bv_len = PAGE_SIZE;
190+
iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
191+
192+
ret = fscache_begin_write_operation(&cres, cookie);
193+
if (ret < 0)
194+
return ret;
195+
196+
ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
197+
no_space_allocated_yet);
198+
if (ret == 0)
199+
ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
200+
fscache_end_operation(&cres);
201+
return ret;
158202
}
159203

160-
void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
204+
/*
205+
* Retrieve a page from FS-Cache
206+
*/
207+
int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
161208
{
162-
struct cifsInodeInfo *cifsi = CIFS_I(inode);
209+
int ret;
163210

164-
WARN_ON(!cifsi->fscache);
211+
cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
212+
__func__, cifs_inode_cookie(inode), page, inode);
165213

214+
ret = fscache_fallback_read_page(inode, page);
215+
if (ret < 0)
216+
return ret;
217+
218+
/* Read completed synchronously */
219+
SetPageUptodate(page);
220+
return 0;
221+
}
222+
223+
void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
224+
{
166225
cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
167-
__func__, cifsi->fscache, page, inode);
226+
__func__, cifs_inode_cookie(inode), page, inode);
227+
228+
fscache_fallback_write_page(inode, page, true);
229+
}
230+
231+
/*
232+
* Query the cache occupancy.
233+
*/
234+
int __cifs_fscache_query_occupancy(struct inode *inode,
235+
pgoff_t first, unsigned int nr_pages,
236+
pgoff_t *_data_first,
237+
unsigned int *_data_nr_pages)
238+
{
239+
struct netfs_cache_resources cres;
240+
struct fscache_cookie *cookie = cifs_inode_cookie(inode);
241+
loff_t start, data_start;
242+
size_t len, data_len;
243+
int ret;
168244

169-
// Needs conversion to using netfslib
245+
ret = fscache_begin_read_operation(&cres, cookie);
246+
if (ret < 0)
247+
return ret;
248+
249+
start = first * PAGE_SIZE;
250+
len = nr_pages * PAGE_SIZE;
251+
ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
252+
&data_start, &data_len);
253+
if (ret == 0) {
254+
*_data_first = data_start / PAGE_SIZE;
255+
*_data_nr_pages = len / PAGE_SIZE;
256+
}
257+
258+
fscache_end_operation(&cres);
259+
return ret;
170260
}

fs/cifs/fscache.h

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef _CIFS_FSCACHE_H
1010
#define _CIFS_FSCACHE_H
1111

12+
#include <linux/swap.h>
1213
#include <linux/fscache.h>
1314

1415
#include "cifsglob.h"
@@ -58,14 +59,6 @@ void cifs_fscache_fill_coherency(struct inode *inode,
5859
}
5960

6061

61-
extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
62-
extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
63-
extern int __cifs_readpages_from_fscache(struct inode *,
64-
struct address_space *,
65-
struct list_head *,
66-
unsigned *);
67-
extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
68-
6962
static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
7063
{
7164
return CIFS_I(inode)->fscache;
@@ -80,33 +73,52 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags
8073
i_size_read(inode), flags);
8174
}
8275

83-
static inline int cifs_readpage_from_fscache(struct inode *inode,
84-
struct page *page)
85-
{
86-
if (CIFS_I(inode)->fscache)
87-
return __cifs_readpage_from_fscache(inode, page);
76+
extern int __cifs_fscache_query_occupancy(struct inode *inode,
77+
pgoff_t first, unsigned int nr_pages,
78+
pgoff_t *_data_first,
79+
unsigned int *_data_nr_pages);
8880

89-
return -ENOBUFS;
81+
static inline int cifs_fscache_query_occupancy(struct inode *inode,
82+
pgoff_t first, unsigned int nr_pages,
83+
pgoff_t *_data_first,
84+
unsigned int *_data_nr_pages)
85+
{
86+
if (!cifs_inode_cookie(inode))
87+
return -ENOBUFS;
88+
return __cifs_fscache_query_occupancy(inode, first, nr_pages,
89+
_data_first, _data_nr_pages);
9090
}
9191

92-
static inline int cifs_readpages_from_fscache(struct inode *inode,
93-
struct address_space *mapping,
94-
struct list_head *pages,
95-
unsigned *nr_pages)
92+
extern int __cifs_readpage_from_fscache(struct inode *pinode, struct page *ppage);
93+
extern void __cifs_readpage_to_fscache(struct inode *pinode, struct page *ppage);
94+
95+
96+
static inline int cifs_readpage_from_fscache(struct inode *inode,
97+
struct page *page)
9698
{
97-
if (CIFS_I(inode)->fscache)
98-
return __cifs_readpages_from_fscache(inode, mapping, pages,
99-
nr_pages);
99+
if (cifs_inode_cookie(inode))
100+
return __cifs_readpage_from_fscache(inode, page);
100101
return -ENOBUFS;
101102
}
102103

103104
static inline void cifs_readpage_to_fscache(struct inode *inode,
104105
struct page *page)
105106
{
106-
if (PageFsCache(page))
107+
if (cifs_inode_cookie(inode))
107108
__cifs_readpage_to_fscache(inode, page);
108109
}
109110

111+
static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
112+
{
113+
if (PageFsCache(page)) {
114+
if (current_is_kswapd() || !(gfp & __GFP_FS))
115+
return false;
116+
wait_on_page_fscache(page);
117+
fscache_note_page_release(cifs_inode_cookie(page->mapping->host));
118+
}
119+
return true;
120+
}
121+
110122
#else /* CONFIG_CIFS_FSCACHE */
111123
static inline
112124
void cifs_fscache_fill_coherency(struct inode *inode,
@@ -123,22 +135,29 @@ static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool upd
123135
static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
124136
static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
125137

126-
static inline int
127-
cifs_readpage_from_fscache(struct inode *inode, struct page *page)
138+
static inline int cifs_fscache_query_occupancy(struct inode *inode,
139+
pgoff_t first, unsigned int nr_pages,
140+
pgoff_t *_data_first,
141+
unsigned int *_data_nr_pages)
128142
{
143+
*_data_first = ULONG_MAX;
144+
*_data_nr_pages = 0;
129145
return -ENOBUFS;
130146
}
131147

132-
static inline int cifs_readpages_from_fscache(struct inode *inode,
133-
struct address_space *mapping,
134-
struct list_head *pages,
135-
unsigned *nr_pages)
148+
static inline int
149+
cifs_readpage_from_fscache(struct inode *inode, struct page *page)
136150
{
137151
return -ENOBUFS;
138152
}
139153

140-
static inline void cifs_readpage_to_fscache(struct inode *inode,
141-
struct page *page) {}
154+
static inline
155+
void cifs_readpage_to_fscache(struct inode *inode, struct page *page) {}
156+
157+
static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
158+
{
159+
return true; /* May release page */
160+
}
142161

143162
#endif /* CONFIG_CIFS_FSCACHE */
144163

0 commit comments

Comments
 (0)