diff options
Diffstat (limited to 'fs/nfsd/filecache.c')
-rw-r--r-- | fs/nfsd/filecache.c | 43 |
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 | ||
218 | static bool | ||
219 | nfsd_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 | |||
231 | static int | ||
232 | nfsd_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 | |||
241 | static bool | ||
242 | nfsd_file_in_use(struct nfsd_file *nf) | ||
243 | { | ||
244 | return nfsd_file_check_writeback(nf) || | ||
245 | nfsd_file_check_write_error(nf); | ||
246 | } | ||
247 | |||
218 | static void | 248 | static void |
219 | nfsd_file_do_unhash(struct nfsd_file *nf) | 249 | nfsd_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 | |||
276 | nfsd_file_put(struct nfsd_file *nf) | 308 | nfsd_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 | ||