summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/filecache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/filecache.c')
-rw-r--r--fs/nfsd/filecache.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index da9e790a055e..ef55e9b1cd4e 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -215,6 +215,36 @@ nfsd_file_free(struct nfsd_file *nf)
215 return flush; 215 return flush;
216} 216}
217 217
218static bool
219nfsd_file_check_writeback(struct nfsd_file *nf)
220{
221 struct file *file = nf->nf_file;
222 struct address_space *mapping;
223
224 if (!file || !(file->f_mode & FMODE_WRITE))
225 return false;
226 mapping = file->f_mapping;
227 return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||
228 mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
229}
230
231static int
232nfsd_file_check_write_error(struct nfsd_file *nf)
233{
234 struct file *file = nf->nf_file;
235
236 if (!file || !(file->f_mode & FMODE_WRITE))
237 return 0;
238 return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err));
239}
240
241static bool
242nfsd_file_in_use(struct nfsd_file *nf)
243{
244 return nfsd_file_check_writeback(nf) ||
245 nfsd_file_check_write_error(nf);
246}
247
218static void 248static void
219nfsd_file_do_unhash(struct nfsd_file *nf) 249nfsd_file_do_unhash(struct nfsd_file *nf)
220{ 250{
@@ -222,6 +252,8 @@ nfsd_file_do_unhash(struct nfsd_file *nf)
222 252
223 trace_nfsd_file_unhash(nf); 253 trace_nfsd_file_unhash(nf);
224 254
255 if (nfsd_file_check_write_error(nf))
256 nfsd_reset_boot_verifier(net_generic(nf->nf_net, nfsd_net_id));
225 --nfsd_file_hashtbl[nf->nf_hashval].nfb_count; 257 --nfsd_file_hashtbl[nf->nf_hashval].nfb_count;
226 hlist_del_rcu(&nf->nf_node); 258 hlist_del_rcu(&nf->nf_node);
227 if (!list_empty(&nf->nf_lru)) 259 if (!list_empty(&nf->nf_lru))
@@ -276,9 +308,10 @@ void
276nfsd_file_put(struct nfsd_file *nf) 308nfsd_file_put(struct nfsd_file *nf)
277{ 309{
278 bool is_hashed = test_bit(NFSD_FILE_HASHED, &nf->nf_flags) != 0; 310 bool is_hashed = test_bit(NFSD_FILE_HASHED, &nf->nf_flags) != 0;
311 bool unused = !nfsd_file_in_use(nf);
279 312
280 set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); 313 set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
281 if (nfsd_file_put_noref(nf) == 1 && is_hashed) 314 if (nfsd_file_put_noref(nf) == 1 && is_hashed && unused)
282 nfsd_file_schedule_laundrette(NFSD_FILE_LAUNDRETTE_MAY_FLUSH); 315 nfsd_file_schedule_laundrette(NFSD_FILE_LAUNDRETTE_MAY_FLUSH);
283} 316}
284 317
@@ -344,6 +377,14 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
344 */ 377 */
345 if (atomic_read(&nf->nf_ref) > 1) 378 if (atomic_read(&nf->nf_ref) > 1)
346 goto out_skip; 379 goto out_skip;
380
381 /*
382 * Don't throw out files that are still undergoing I/O or
383 * that have uncleared errors pending.
384 */
385 if (nfsd_file_check_writeback(nf))
386 goto out_skip;
387
347 if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) 388 if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags))
348 goto out_rescan; 389 goto out_rescan;
349 390