1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Meta data file for NILFS |
4 | * |
5 | * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. |
6 | * |
7 | * Written by Ryusuke Konishi. |
8 | */ |
9 | |
10 | #include <linux/buffer_head.h> |
11 | #include <linux/mpage.h> |
12 | #include <linux/mm.h> |
13 | #include <linux/writeback.h> |
14 | #include <linux/backing-dev.h> |
15 | #include <linux/swap.h> |
16 | #include <linux/slab.h> |
17 | #include "nilfs.h" |
18 | #include "btnode.h" |
19 | #include "segment.h" |
20 | #include "page.h" |
21 | #include "mdt.h" |
22 | #include "alloc.h" /* nilfs_palloc_destroy_cache() */ |
23 | |
24 | #include <trace/events/nilfs2.h> |
25 | |
26 | #define NILFS_MDT_MAX_RA_BLOCKS (16 - 1) |
27 | |
28 | |
29 | static int |
30 | nilfs_mdt_insert_new_block(struct inode *inode, unsigned long block, |
31 | struct buffer_head *bh, |
32 | void (*init_block)(struct inode *, |
33 | struct buffer_head *, void *)) |
34 | { |
35 | struct nilfs_inode_info *ii = NILFS_I(inode); |
36 | void *kaddr; |
37 | int ret; |
38 | |
39 | /* Caller exclude read accesses using page lock */ |
40 | |
41 | /* set_buffer_new(bh); */ |
42 | bh->b_blocknr = 0; |
43 | |
44 | ret = nilfs_bmap_insert(bmap: ii->i_bmap, key: block, rec: (unsigned long)bh); |
45 | if (unlikely(ret)) |
46 | return ret; |
47 | |
48 | set_buffer_mapped(bh); |
49 | |
50 | kaddr = kmap_atomic(page: bh->b_page); |
51 | memset(kaddr + bh_offset(bh), 0, i_blocksize(inode)); |
52 | if (init_block) |
53 | init_block(inode, bh, kaddr); |
54 | flush_dcache_page(page: bh->b_page); |
55 | kunmap_atomic(kaddr); |
56 | |
57 | set_buffer_uptodate(bh); |
58 | mark_buffer_dirty(bh); |
59 | nilfs_mdt_mark_dirty(inode); |
60 | |
61 | trace_nilfs2_mdt_insert_new_block(inode, ino: inode->i_ino, block); |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, |
67 | struct buffer_head **out_bh, |
68 | void (*init_block)(struct inode *, |
69 | struct buffer_head *, |
70 | void *)) |
71 | { |
72 | struct super_block *sb = inode->i_sb; |
73 | struct nilfs_transaction_info ti; |
74 | struct buffer_head *bh; |
75 | int err; |
76 | |
77 | nilfs_transaction_begin(sb, &ti, 0); |
78 | |
79 | err = -ENOMEM; |
80 | bh = nilfs_grab_buffer(inode, inode->i_mapping, block, 0); |
81 | if (unlikely(!bh)) |
82 | goto failed_unlock; |
83 | |
84 | err = -EEXIST; |
85 | if (buffer_uptodate(bh)) |
86 | goto failed_bh; |
87 | |
88 | wait_on_buffer(bh); |
89 | if (buffer_uptodate(bh)) |
90 | goto failed_bh; |
91 | |
92 | bh->b_bdev = sb->s_bdev; |
93 | err = nilfs_mdt_insert_new_block(inode, block, bh, init_block); |
94 | if (likely(!err)) { |
95 | get_bh(bh); |
96 | *out_bh = bh; |
97 | } |
98 | |
99 | failed_bh: |
100 | unlock_page(page: bh->b_page); |
101 | put_page(page: bh->b_page); |
102 | brelse(bh); |
103 | |
104 | failed_unlock: |
105 | if (likely(!err)) |
106 | err = nilfs_transaction_commit(sb); |
107 | else |
108 | nilfs_transaction_abort(sb); |
109 | |
110 | return err; |
111 | } |
112 | |
113 | static int |
114 | nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, blk_opf_t opf, |
115 | struct buffer_head **out_bh) |
116 | { |
117 | struct buffer_head *bh; |
118 | __u64 blknum = 0; |
119 | int ret = -ENOMEM; |
120 | |
121 | bh = nilfs_grab_buffer(inode, inode->i_mapping, blkoff, 0); |
122 | if (unlikely(!bh)) |
123 | goto failed; |
124 | |
125 | ret = -EEXIST; /* internal code */ |
126 | if (buffer_uptodate(bh)) |
127 | goto out; |
128 | |
129 | if (opf & REQ_RAHEAD) { |
130 | if (!trylock_buffer(bh)) { |
131 | ret = -EBUSY; |
132 | goto failed_bh; |
133 | } |
134 | } else /* opf == REQ_OP_READ */ |
135 | lock_buffer(bh); |
136 | |
137 | if (buffer_uptodate(bh)) { |
138 | unlock_buffer(bh); |
139 | goto out; |
140 | } |
141 | |
142 | ret = nilfs_bmap_lookup(bmap: NILFS_I(inode)->i_bmap, key: blkoff, ptr: &blknum); |
143 | if (unlikely(ret)) { |
144 | unlock_buffer(bh); |
145 | goto failed_bh; |
146 | } |
147 | map_bh(bh, sb: inode->i_sb, block: (sector_t)blknum); |
148 | |
149 | bh->b_end_io = end_buffer_read_sync; |
150 | get_bh(bh); |
151 | submit_bh(opf, bh); |
152 | ret = 0; |
153 | |
154 | trace_nilfs2_mdt_submit_block(inode, ino: inode->i_ino, blkoff, |
155 | mode: opf & REQ_OP_MASK); |
156 | out: |
157 | get_bh(bh); |
158 | *out_bh = bh; |
159 | |
160 | failed_bh: |
161 | unlock_page(page: bh->b_page); |
162 | put_page(page: bh->b_page); |
163 | brelse(bh); |
164 | failed: |
165 | return ret; |
166 | } |
167 | |
168 | static int nilfs_mdt_read_block(struct inode *inode, unsigned long block, |
169 | int readahead, struct buffer_head **out_bh) |
170 | { |
171 | struct buffer_head *first_bh, *bh; |
172 | unsigned long blkoff; |
173 | int i, nr_ra_blocks = NILFS_MDT_MAX_RA_BLOCKS; |
174 | int err; |
175 | |
176 | err = nilfs_mdt_submit_block(inode, blkoff: block, opf: REQ_OP_READ, out_bh: &first_bh); |
177 | if (err == -EEXIST) /* internal code */ |
178 | goto out; |
179 | |
180 | if (unlikely(err)) |
181 | goto failed; |
182 | |
183 | if (readahead) { |
184 | blkoff = block + 1; |
185 | for (i = 0; i < nr_ra_blocks; i++, blkoff++) { |
186 | err = nilfs_mdt_submit_block(inode, blkoff, |
187 | opf: REQ_OP_READ | REQ_RAHEAD, out_bh: &bh); |
188 | if (likely(!err || err == -EEXIST)) |
189 | brelse(bh); |
190 | else if (err != -EBUSY) |
191 | break; |
192 | /* abort readahead if bmap lookup failed */ |
193 | if (!buffer_locked(bh: first_bh)) |
194 | goto out_no_wait; |
195 | } |
196 | } |
197 | |
198 | wait_on_buffer(bh: first_bh); |
199 | |
200 | out_no_wait: |
201 | err = -EIO; |
202 | if (!buffer_uptodate(bh: first_bh)) { |
203 | nilfs_err(inode->i_sb, |
204 | "I/O error reading meta-data file (ino=%lu, block-offset=%lu)" , |
205 | inode->i_ino, block); |
206 | goto failed_bh; |
207 | } |
208 | out: |
209 | *out_bh = first_bh; |
210 | return 0; |
211 | |
212 | failed_bh: |
213 | brelse(bh: first_bh); |
214 | failed: |
215 | return err; |
216 | } |
217 | |
218 | /** |
219 | * nilfs_mdt_get_block - read or create a buffer on meta data file. |
220 | * @inode: inode of the meta data file |
221 | * @blkoff: block offset |
222 | * @create: create flag |
223 | * @init_block: initializer used for newly allocated block |
224 | * @out_bh: output of a pointer to the buffer_head |
225 | * |
226 | * nilfs_mdt_get_block() looks up the specified buffer and tries to create |
227 | * a new buffer if @create is not zero. On success, the returned buffer is |
228 | * assured to be either existing or formatted using a buffer lock on success. |
229 | * @out_bh is substituted only when zero is returned. |
230 | * |
231 | * Return Value: On success, it returns 0. On error, the following negative |
232 | * error code is returned. |
233 | * |
234 | * %-ENOMEM - Insufficient memory available. |
235 | * |
236 | * %-EIO - I/O error |
237 | * |
238 | * %-ENOENT - the specified block does not exist (hole block) |
239 | * |
240 | * %-EROFS - Read only filesystem (for create mode) |
241 | */ |
242 | int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, |
243 | void (*init_block)(struct inode *, |
244 | struct buffer_head *, void *), |
245 | struct buffer_head **out_bh) |
246 | { |
247 | int ret; |
248 | |
249 | /* Should be rewritten with merging nilfs_mdt_read_block() */ |
250 | retry: |
251 | ret = nilfs_mdt_read_block(inode, block: blkoff, readahead: !create, out_bh); |
252 | if (!create || ret != -ENOENT) |
253 | return ret; |
254 | |
255 | ret = nilfs_mdt_create_block(inode, block: blkoff, out_bh, init_block); |
256 | if (unlikely(ret == -EEXIST)) { |
257 | /* create = 0; */ /* limit read-create loop retries */ |
258 | goto retry; |
259 | } |
260 | return ret; |
261 | } |
262 | |
263 | /** |
264 | * nilfs_mdt_find_block - find and get a buffer on meta data file. |
265 | * @inode: inode of the meta data file |
266 | * @start: start block offset (inclusive) |
267 | * @end: end block offset (inclusive) |
268 | * @blkoff: block offset |
269 | * @out_bh: place to store a pointer to buffer_head struct |
270 | * |
271 | * nilfs_mdt_find_block() looks up an existing block in range of |
272 | * [@start, @end] and stores pointer to a buffer head of the block to |
273 | * @out_bh, and block offset to @blkoff, respectively. @out_bh and |
274 | * @blkoff are substituted only when zero is returned. |
275 | * |
276 | * Return Value: On success, it returns 0. On error, the following negative |
277 | * error code is returned. |
278 | * |
279 | * %-ENOMEM - Insufficient memory available. |
280 | * |
281 | * %-EIO - I/O error |
282 | * |
283 | * %-ENOENT - no block was found in the range |
284 | */ |
285 | int nilfs_mdt_find_block(struct inode *inode, unsigned long start, |
286 | unsigned long end, unsigned long *blkoff, |
287 | struct buffer_head **out_bh) |
288 | { |
289 | __u64 next; |
290 | int ret; |
291 | |
292 | if (unlikely(start > end)) |
293 | return -ENOENT; |
294 | |
295 | ret = nilfs_mdt_read_block(inode, block: start, readahead: true, out_bh); |
296 | if (!ret) { |
297 | *blkoff = start; |
298 | goto out; |
299 | } |
300 | if (unlikely(ret != -ENOENT || start == ULONG_MAX)) |
301 | goto out; |
302 | |
303 | ret = nilfs_bmap_seek_key(bmap: NILFS_I(inode)->i_bmap, start: start + 1, keyp: &next); |
304 | if (!ret) { |
305 | if (next <= end) { |
306 | ret = nilfs_mdt_read_block(inode, block: next, readahead: true, out_bh); |
307 | if (!ret) |
308 | *blkoff = next; |
309 | } else { |
310 | ret = -ENOENT; |
311 | } |
312 | } |
313 | out: |
314 | return ret; |
315 | } |
316 | |
317 | /** |
318 | * nilfs_mdt_delete_block - make a hole on the meta data file. |
319 | * @inode: inode of the meta data file |
320 | * @block: block offset |
321 | * |
322 | * Return Value: On success, zero is returned. |
323 | * On error, one of the following negative error code is returned. |
324 | * |
325 | * %-ENOMEM - Insufficient memory available. |
326 | * |
327 | * %-EIO - I/O error |
328 | */ |
329 | int nilfs_mdt_delete_block(struct inode *inode, unsigned long block) |
330 | { |
331 | struct nilfs_inode_info *ii = NILFS_I(inode); |
332 | int err; |
333 | |
334 | err = nilfs_bmap_delete(bmap: ii->i_bmap, key: block); |
335 | if (!err || err == -ENOENT) { |
336 | nilfs_mdt_mark_dirty(inode); |
337 | nilfs_mdt_forget_block(inode, block); |
338 | } |
339 | return err; |
340 | } |
341 | |
342 | /** |
343 | * nilfs_mdt_forget_block - discard dirty state and try to remove the page |
344 | * @inode: inode of the meta data file |
345 | * @block: block offset |
346 | * |
347 | * nilfs_mdt_forget_block() clears a dirty flag of the specified buffer, and |
348 | * tries to release the page including the buffer from a page cache. |
349 | * |
350 | * Return Value: On success, 0 is returned. On error, one of the following |
351 | * negative error code is returned. |
352 | * |
353 | * %-EBUSY - page has an active buffer. |
354 | * |
355 | * %-ENOENT - page cache has no page addressed by the offset. |
356 | */ |
357 | int nilfs_mdt_forget_block(struct inode *inode, unsigned long block) |
358 | { |
359 | pgoff_t index = block >> (PAGE_SHIFT - inode->i_blkbits); |
360 | struct folio *folio; |
361 | struct buffer_head *bh; |
362 | int ret = 0; |
363 | int still_dirty; |
364 | |
365 | folio = filemap_lock_folio(mapping: inode->i_mapping, index); |
366 | if (IS_ERR(ptr: folio)) |
367 | return -ENOENT; |
368 | |
369 | folio_wait_writeback(folio); |
370 | |
371 | bh = folio_buffers(folio); |
372 | if (bh) { |
373 | unsigned long first_block = index << |
374 | (PAGE_SHIFT - inode->i_blkbits); |
375 | bh = get_nth_bh(bh, count: block - first_block); |
376 | nilfs_forget_buffer(bh); |
377 | } |
378 | still_dirty = folio_test_dirty(folio); |
379 | folio_unlock(folio); |
380 | folio_put(folio); |
381 | |
382 | if (still_dirty || |
383 | invalidate_inode_pages2_range(mapping: inode->i_mapping, start: index, end: index) != 0) |
384 | ret = -EBUSY; |
385 | return ret; |
386 | } |
387 | |
388 | int nilfs_mdt_fetch_dirty(struct inode *inode) |
389 | { |
390 | struct nilfs_inode_info *ii = NILFS_I(inode); |
391 | |
392 | if (nilfs_bmap_test_and_clear_dirty(ii->i_bmap)) { |
393 | set_bit(nr: NILFS_I_DIRTY, addr: &ii->i_state); |
394 | return 1; |
395 | } |
396 | return test_bit(NILFS_I_DIRTY, &ii->i_state); |
397 | } |
398 | |
399 | static int |
400 | nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) |
401 | { |
402 | struct inode *inode = page->mapping->host; |
403 | struct super_block *sb; |
404 | int err = 0; |
405 | |
406 | if (inode && sb_rdonly(sb: inode->i_sb)) { |
407 | /* |
408 | * It means that filesystem was remounted in read-only |
409 | * mode because of error or metadata corruption. But we |
410 | * have dirty pages that try to be flushed in background. |
411 | * So, here we simply discard this dirty page. |
412 | */ |
413 | nilfs_clear_dirty_page(page, false); |
414 | unlock_page(page); |
415 | return -EROFS; |
416 | } |
417 | |
418 | redirty_page_for_writepage(wbc, page); |
419 | unlock_page(page); |
420 | |
421 | if (!inode) |
422 | return 0; |
423 | |
424 | sb = inode->i_sb; |
425 | |
426 | if (wbc->sync_mode == WB_SYNC_ALL) |
427 | err = nilfs_construct_segment(sb); |
428 | else if (wbc->for_reclaim) |
429 | nilfs_flush_segment(sb, inode->i_ino); |
430 | |
431 | return err; |
432 | } |
433 | |
434 | |
435 | static const struct address_space_operations def_mdt_aops = { |
436 | .dirty_folio = block_dirty_folio, |
437 | .invalidate_folio = block_invalidate_folio, |
438 | .writepage = nilfs_mdt_write_page, |
439 | }; |
440 | |
441 | static const struct inode_operations def_mdt_iops; |
442 | static const struct file_operations def_mdt_fops; |
443 | |
444 | |
445 | int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz) |
446 | { |
447 | struct nilfs_mdt_info *mi; |
448 | |
449 | mi = kzalloc(max(sizeof(*mi), objsz), GFP_NOFS); |
450 | if (!mi) |
451 | return -ENOMEM; |
452 | |
453 | init_rwsem(&mi->mi_sem); |
454 | inode->i_private = mi; |
455 | |
456 | inode->i_mode = S_IFREG; |
457 | mapping_set_gfp_mask(m: inode->i_mapping, mask: gfp_mask); |
458 | |
459 | inode->i_op = &def_mdt_iops; |
460 | inode->i_fop = &def_mdt_fops; |
461 | inode->i_mapping->a_ops = &def_mdt_aops; |
462 | |
463 | return 0; |
464 | } |
465 | |
466 | /** |
467 | * nilfs_mdt_clear - do cleanup for the metadata file |
468 | * @inode: inode of the metadata file |
469 | */ |
470 | void nilfs_mdt_clear(struct inode *inode) |
471 | { |
472 | struct nilfs_mdt_info *mdi = NILFS_MDT(inode); |
473 | struct nilfs_shadow_map *shadow = mdi->mi_shadow; |
474 | |
475 | if (mdi->mi_palloc_cache) |
476 | nilfs_palloc_destroy_cache(inode); |
477 | |
478 | if (shadow) { |
479 | struct inode *s_inode = shadow->inode; |
480 | |
481 | shadow->inode = NULL; |
482 | iput(s_inode); |
483 | mdi->mi_shadow = NULL; |
484 | } |
485 | } |
486 | |
487 | /** |
488 | * nilfs_mdt_destroy - release resources used by the metadata file |
489 | * @inode: inode of the metadata file |
490 | */ |
491 | void nilfs_mdt_destroy(struct inode *inode) |
492 | { |
493 | struct nilfs_mdt_info *mdi = NILFS_MDT(inode); |
494 | |
495 | kfree(objp: mdi->mi_bgl); /* kfree(NULL) is safe */ |
496 | kfree(objp: mdi); |
497 | } |
498 | |
499 | void nilfs_mdt_set_entry_size(struct inode *inode, unsigned int entry_size, |
500 | unsigned int ) |
501 | { |
502 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); |
503 | |
504 | mi->mi_entry_size = entry_size; |
505 | mi->mi_entries_per_block = i_blocksize(node: inode) / entry_size; |
506 | mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size); |
507 | } |
508 | |
509 | /** |
510 | * nilfs_mdt_setup_shadow_map - setup shadow map and bind it to metadata file |
511 | * @inode: inode of the metadata file |
512 | * @shadow: shadow mapping |
513 | */ |
514 | int nilfs_mdt_setup_shadow_map(struct inode *inode, |
515 | struct nilfs_shadow_map *shadow) |
516 | { |
517 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); |
518 | struct inode *s_inode; |
519 | |
520 | INIT_LIST_HEAD(list: &shadow->frozen_buffers); |
521 | |
522 | s_inode = nilfs_iget_for_shadow(inode); |
523 | if (IS_ERR(ptr: s_inode)) |
524 | return PTR_ERR(ptr: s_inode); |
525 | |
526 | shadow->inode = s_inode; |
527 | mi->mi_shadow = shadow; |
528 | return 0; |
529 | } |
530 | |
531 | /** |
532 | * nilfs_mdt_save_to_shadow_map - copy bmap and dirty pages to shadow map |
533 | * @inode: inode of the metadata file |
534 | */ |
535 | int nilfs_mdt_save_to_shadow_map(struct inode *inode) |
536 | { |
537 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); |
538 | struct nilfs_inode_info *ii = NILFS_I(inode); |
539 | struct nilfs_shadow_map *shadow = mi->mi_shadow; |
540 | struct inode *s_inode = shadow->inode; |
541 | int ret; |
542 | |
543 | ret = nilfs_copy_dirty_pages(s_inode->i_mapping, inode->i_mapping); |
544 | if (ret) |
545 | goto out; |
546 | |
547 | ret = nilfs_copy_dirty_pages(NILFS_I(inode: s_inode)->i_assoc_inode->i_mapping, |
548 | ii->i_assoc_inode->i_mapping); |
549 | if (ret) |
550 | goto out; |
551 | |
552 | nilfs_bmap_save(ii->i_bmap, &shadow->bmap_store); |
553 | out: |
554 | return ret; |
555 | } |
556 | |
557 | int nilfs_mdt_freeze_buffer(struct inode *inode, struct buffer_head *bh) |
558 | { |
559 | struct nilfs_shadow_map *shadow = NILFS_MDT(inode)->mi_shadow; |
560 | struct buffer_head *bh_frozen; |
561 | struct folio *folio; |
562 | int blkbits = inode->i_blkbits; |
563 | |
564 | folio = filemap_grab_folio(mapping: shadow->inode->i_mapping, |
565 | index: bh->b_folio->index); |
566 | if (IS_ERR(ptr: folio)) |
567 | return PTR_ERR(ptr: folio); |
568 | |
569 | bh_frozen = folio_buffers(folio); |
570 | if (!bh_frozen) |
571 | bh_frozen = create_empty_buffers(folio, blocksize: 1 << blkbits, b_state: 0); |
572 | |
573 | bh_frozen = get_nth_bh(bh: bh_frozen, count: bh_offset(bh) >> blkbits); |
574 | |
575 | if (!buffer_uptodate(bh: bh_frozen)) |
576 | nilfs_copy_buffer(bh_frozen, bh); |
577 | if (list_empty(head: &bh_frozen->b_assoc_buffers)) { |
578 | list_add_tail(new: &bh_frozen->b_assoc_buffers, |
579 | head: &shadow->frozen_buffers); |
580 | set_buffer_nilfs_redirected(bh); |
581 | } else { |
582 | brelse(bh: bh_frozen); /* already frozen */ |
583 | } |
584 | |
585 | folio_unlock(folio); |
586 | folio_put(folio); |
587 | return 0; |
588 | } |
589 | |
590 | struct buffer_head * |
591 | nilfs_mdt_get_frozen_buffer(struct inode *inode, struct buffer_head *bh) |
592 | { |
593 | struct nilfs_shadow_map *shadow = NILFS_MDT(inode)->mi_shadow; |
594 | struct buffer_head *bh_frozen = NULL; |
595 | struct folio *folio; |
596 | int n; |
597 | |
598 | folio = filemap_lock_folio(mapping: shadow->inode->i_mapping, |
599 | index: bh->b_folio->index); |
600 | if (!IS_ERR(ptr: folio)) { |
601 | bh_frozen = folio_buffers(folio); |
602 | if (bh_frozen) { |
603 | n = bh_offset(bh) >> inode->i_blkbits; |
604 | bh_frozen = get_nth_bh(bh: bh_frozen, count: n); |
605 | } |
606 | folio_unlock(folio); |
607 | folio_put(folio); |
608 | } |
609 | return bh_frozen; |
610 | } |
611 | |
612 | static void nilfs_release_frozen_buffers(struct nilfs_shadow_map *shadow) |
613 | { |
614 | struct list_head *head = &shadow->frozen_buffers; |
615 | struct buffer_head *bh; |
616 | |
617 | while (!list_empty(head)) { |
618 | bh = list_first_entry(head, struct buffer_head, |
619 | b_assoc_buffers); |
620 | list_del_init(entry: &bh->b_assoc_buffers); |
621 | brelse(bh); /* drop ref-count to make it releasable */ |
622 | } |
623 | } |
624 | |
625 | /** |
626 | * nilfs_mdt_restore_from_shadow_map - restore dirty pages and bmap state |
627 | * @inode: inode of the metadata file |
628 | */ |
629 | void nilfs_mdt_restore_from_shadow_map(struct inode *inode) |
630 | { |
631 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); |
632 | struct nilfs_inode_info *ii = NILFS_I(inode); |
633 | struct nilfs_shadow_map *shadow = mi->mi_shadow; |
634 | |
635 | down_write(sem: &mi->mi_sem); |
636 | |
637 | if (mi->mi_palloc_cache) |
638 | nilfs_palloc_clear_cache(inode); |
639 | |
640 | nilfs_clear_dirty_pages(inode->i_mapping, true); |
641 | nilfs_copy_back_pages(inode->i_mapping, shadow->inode->i_mapping); |
642 | |
643 | nilfs_clear_dirty_pages(ii->i_assoc_inode->i_mapping, true); |
644 | nilfs_copy_back_pages(ii->i_assoc_inode->i_mapping, |
645 | NILFS_I(inode: shadow->inode)->i_assoc_inode->i_mapping); |
646 | |
647 | nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store); |
648 | |
649 | up_write(sem: &mi->mi_sem); |
650 | } |
651 | |
652 | /** |
653 | * nilfs_mdt_clear_shadow_map - truncate pages in shadow map caches |
654 | * @inode: inode of the metadata file |
655 | */ |
656 | void nilfs_mdt_clear_shadow_map(struct inode *inode) |
657 | { |
658 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); |
659 | struct nilfs_shadow_map *shadow = mi->mi_shadow; |
660 | struct inode *shadow_btnc_inode = NILFS_I(inode: shadow->inode)->i_assoc_inode; |
661 | |
662 | down_write(sem: &mi->mi_sem); |
663 | nilfs_release_frozen_buffers(shadow); |
664 | truncate_inode_pages(shadow->inode->i_mapping, 0); |
665 | truncate_inode_pages(shadow_btnc_inode->i_mapping, 0); |
666 | up_write(sem: &mi->mi_sem); |
667 | } |
668 | |