23 #include <linux/kernel.h>
25 #include <linux/string.h>
27 #include <linux/errno.h>
33 static inline unsigned long
34 nilfs_cpfile_checkpoints_per_block(
const struct inode *cpfile)
36 return NILFS_MDT(cpfile)->mi_entries_per_block;
41 nilfs_cpfile_get_blkoff(
const struct inode *cpfile,
__u64 cno)
43 __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
44 do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
45 return (
unsigned long)tcno;
50 nilfs_cpfile_get_offset(
const struct inode *cpfile,
__u64 cno)
52 __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
53 return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
57 nilfs_cpfile_checkpoints_in_block(
const struct inode *cpfile,
62 nilfs_cpfile_checkpoints_per_block(cpfile) -
63 nilfs_cpfile_get_offset(cpfile, curr),
67 static inline int nilfs_cpfile_is_in_first(
const struct inode *cpfile,
70 return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;
74 nilfs_cpfile_block_add_valid_checkpoints(
const struct inode *cpfile,
75 struct buffer_head *bh,
88 nilfs_cpfile_block_sub_valid_checkpoints(
const struct inode *cpfile,
89 struct buffer_head *bh,
103 nilfs_cpfile_block_get_header(
const struct inode *cpfile,
104 struct buffer_head *bh,
107 return kaddr + bh_offset(bh);
111 nilfs_cpfile_block_get_checkpoint(
const struct inode *cpfile,
__u64 cno,
112 struct buffer_head *bh,
115 return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *
116 NILFS_MDT(cpfile)->mi_entry_size;
119 static void nilfs_cpfile_block_init(
struct inode *cpfile,
120 struct buffer_head *bh,
124 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
125 int n = nilfs_cpfile_checkpoints_per_block(cpfile);
128 nilfs_checkpoint_set_invalid(cp);
129 cp = (
void *)cp + cpsz;
133 static inline int nilfs_cpfile_get_header_block(
struct inode *cpfile,
134 struct buffer_head **bhp)
139 static inline int nilfs_cpfile_get_checkpoint_block(
struct inode *cpfile,
142 struct buffer_head **bhp)
145 nilfs_cpfile_get_blkoff(cpfile, cno),
146 create, nilfs_cpfile_block_init, bhp);
149 static inline int nilfs_cpfile_delete_checkpoint_block(
struct inode *cpfile,
153 nilfs_cpfile_get_blkoff(cpfile, cno));
185 struct buffer_head **bhp)
187 struct buffer_head *header_bh, *cp_bh;
193 if (
unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) ||
194 (cno < nilfs_mdt_cno(cpfile) && create)))
199 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
202 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh);
205 kaddr =
kmap(cp_bh->b_page);
206 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
207 if (nilfs_checkpoint_invalid(cp)) {
215 nilfs_checkpoint_clear_invalid(cp);
216 if (!nilfs_cpfile_is_in_first(cpfile, cno))
217 nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
222 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
227 nilfs_mdt_mark_dirty(cpfile);
238 up_write(&NILFS_MDT(cpfile)->mi_sem);
253 struct buffer_head *bh)
282 struct buffer_head *header_bh, *cp_bh;
285 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
288 unsigned long tnicps;
291 if (
unlikely(start == 0 || start > end)) {
293 "[%llu, %llu)\n", __func__,
294 (
unsigned long long)start, (
unsigned long long)end);
300 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
306 for (cno = start; cno <
end; cno += ncps) {
307 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
308 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
318 cp = nilfs_cpfile_block_get_checkpoint(
319 cpfile, cno, cp_bh, kaddr);
321 for (i = 0; i < ncps; i++, cp = (
void *)cp + cpsz) {
322 if (nilfs_checkpoint_snapshot(cp)) {
324 }
else if (!nilfs_checkpoint_invalid(cp)) {
325 nilfs_checkpoint_set_invalid(cp);
332 nilfs_mdt_mark_dirty(cpfile);
333 if (!nilfs_cpfile_is_in_first(cpfile, cno)) {
335 nilfs_cpfile_block_sub_valid_checkpoints(
336 cpfile, cp_bh, kaddr, nicps);
342 nilfs_cpfile_delete_checkpoint_block(
347 "%s: cannot delete block\n",
360 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
364 nilfs_mdt_mark_dirty(cpfile);
373 up_write(&NILFS_MDT(cpfile)->mi_sem);
377 static void nilfs_cpfile_checkpoint_to_cpinfo(
struct inode *cpfile,
391 void *
buf,
unsigned cisz,
size_t nci)
395 struct buffer_head *bh;
396 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
397 __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
406 for (n = 0; cno < cur_cno && n < nci; cno += ncps) {
407 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
408 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
416 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
417 for (i = 0; i < ncps && n < nci; i++, cp = (
void *)cp + cpsz) {
418 if (!nilfs_checkpoint_invalid(cp)) {
419 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
421 ci = (
void *)ci + cisz;
431 ci = (
void *)ci - cisz;
436 up_read(&NILFS_MDT(cpfile)->mi_sem);
441 void *buf,
unsigned cisz,
size_t nci)
443 struct buffer_head *bh;
448 unsigned long curr_blkoff, next_blkoff;
455 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
459 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
472 curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
473 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
481 cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);
483 if (
unlikely(nilfs_checkpoint_invalid(cp) ||
484 !nilfs_checkpoint_snapshot(cp)))
486 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
487 ci = (
void *)ci + cisz;
493 next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
494 if (curr_blkoff != next_blkoff) {
497 ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
506 curr_blkoff = next_blkoff;
514 up_read(&NILFS_MDT(cpfile)->mi_sem);
527 void *buf,
unsigned cisz,
size_t nci)
531 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
533 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
550 nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci,
sizeof(ci), 1);
553 else if (nci == 0 || ci.
ci_cno != cno)
555 else if (nilfs_cpinfo_snapshot(&ci))
562 nilfs_cpfile_block_get_snapshot_list(
const struct inode *cpfile,
564 struct buffer_head *bh,
572 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
575 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
581 static int nilfs_cpfile_set_snapshot(
struct inode *cpfile,
__u64 cno)
583 struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
588 unsigned long curr_blkoff, prev_blkoff;
596 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
600 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
601 if (nilfs_checkpoint_invalid(cp)) {
606 if (nilfs_checkpoint_snapshot(cp)) {
613 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
617 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
625 prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
627 if (curr_blkoff != prev_blkoff) {
630 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
636 curr_blkoff = prev_blkoff;
637 cp = nilfs_cpfile_block_get_checkpoint(
638 cpfile, curr, curr_bh, kaddr);
645 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
655 list = nilfs_cpfile_block_get_snapshot_list(
656 cpfile, curr, curr_bh, kaddr);
661 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
664 nilfs_checkpoint_set_snapshot(cp);
668 list = nilfs_cpfile_block_get_snapshot_list(
669 cpfile, prev, prev_bh, kaddr);
674 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
682 nilfs_mdt_mark_dirty(cpfile);
696 up_write(&NILFS_MDT(cpfile)->mi_sem);
700 static int nilfs_cpfile_clear_snapshot(
struct inode *cpfile,
__u64 cno)
702 struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
714 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
718 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
719 if (nilfs_checkpoint_invalid(cp)) {
724 if (!nilfs_checkpoint_snapshot(cp)) {
735 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
739 ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
748 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
758 list = nilfs_cpfile_block_get_snapshot_list(
759 cpfile, next, next_bh, kaddr);
764 list = nilfs_cpfile_block_get_snapshot_list(
765 cpfile, prev, prev_bh, kaddr);
770 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
773 nilfs_checkpoint_clear_snapshot(cp);
777 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
785 nilfs_mdt_mark_dirty(cpfile);
799 up_write(&NILFS_MDT(cpfile)->mi_sem);
822 struct buffer_head *bh;
829 if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))
833 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
837 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
838 if (nilfs_checkpoint_invalid(cp))
841 ret = nilfs_checkpoint_snapshot(cp);
846 up_read(&NILFS_MDT(cpfile)->mi_sem);
883 ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
886 return nilfs_cpfile_set_snapshot(cpfile, cno);
909 struct buffer_head *bh;
916 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
920 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
921 cpstat->
cs_cno = nilfs_mdt_cno(cpfile);
928 up_read(&NILFS_MDT(cpfile)->mi_sem);
942 struct inode *cpfile;