0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/fs.h>
0012 #include <linux/string.h>
0013 #include <linux/buffer_head.h>
0014 #include <linux/errno.h>
0015 #include "mdt.h"
0016 #include "cpfile.h"
0017
0018
0019 static inline unsigned long
0020 nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile)
0021 {
0022 return NILFS_MDT(cpfile)->mi_entries_per_block;
0023 }
0024
0025
0026 static unsigned long
0027 nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno)
0028 {
0029 __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
0030
0031 do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
0032 return (unsigned long)tcno;
0033 }
0034
0035
0036 static unsigned long
0037 nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)
0038 {
0039 __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
0040
0041 return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
0042 }
0043
0044 static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile,
0045 unsigned long blkoff)
0046 {
0047 return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff
0048 + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;
0049 }
0050
0051 static unsigned long
0052 nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
0053 __u64 curr,
0054 __u64 max)
0055 {
0056 return min_t(__u64,
0057 nilfs_cpfile_checkpoints_per_block(cpfile) -
0058 nilfs_cpfile_get_offset(cpfile, curr),
0059 max - curr);
0060 }
0061
0062 static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile,
0063 __u64 cno)
0064 {
0065 return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;
0066 }
0067
0068 static unsigned int
0069 nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,
0070 struct buffer_head *bh,
0071 void *kaddr,
0072 unsigned int n)
0073 {
0074 struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
0075 unsigned int count;
0076
0077 count = le32_to_cpu(cp->cp_checkpoints_count) + n;
0078 cp->cp_checkpoints_count = cpu_to_le32(count);
0079 return count;
0080 }
0081
0082 static unsigned int
0083 nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,
0084 struct buffer_head *bh,
0085 void *kaddr,
0086 unsigned int n)
0087 {
0088 struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
0089 unsigned int count;
0090
0091 WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);
0092 count = le32_to_cpu(cp->cp_checkpoints_count) - n;
0093 cp->cp_checkpoints_count = cpu_to_le32(count);
0094 return count;
0095 }
0096
0097 static inline struct nilfs_cpfile_header *
0098 nilfs_cpfile_block_get_header(const struct inode *cpfile,
0099 struct buffer_head *bh,
0100 void *kaddr)
0101 {
0102 return kaddr + bh_offset(bh);
0103 }
0104
0105 static struct nilfs_checkpoint *
0106 nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno,
0107 struct buffer_head *bh,
0108 void *kaddr)
0109 {
0110 return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *
0111 NILFS_MDT(cpfile)->mi_entry_size;
0112 }
0113
0114 static void nilfs_cpfile_block_init(struct inode *cpfile,
0115 struct buffer_head *bh,
0116 void *kaddr)
0117 {
0118 struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
0119 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
0120 int n = nilfs_cpfile_checkpoints_per_block(cpfile);
0121
0122 while (n-- > 0) {
0123 nilfs_checkpoint_set_invalid(cp);
0124 cp = (void *)cp + cpsz;
0125 }
0126 }
0127
0128 static inline int nilfs_cpfile_get_header_block(struct inode *cpfile,
0129 struct buffer_head **bhp)
0130 {
0131 return nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);
0132 }
0133
0134 static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
0135 __u64 cno,
0136 int create,
0137 struct buffer_head **bhp)
0138 {
0139 return nilfs_mdt_get_block(cpfile,
0140 nilfs_cpfile_get_blkoff(cpfile, cno),
0141 create, nilfs_cpfile_block_init, bhp);
0142 }
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
0162 __u64 start_cno, __u64 end_cno,
0163 __u64 *cnop,
0164 struct buffer_head **bhp)
0165 {
0166 unsigned long start, end, blkoff;
0167 int ret;
0168
0169 if (unlikely(start_cno > end_cno))
0170 return -ENOENT;
0171
0172 start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
0173 end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
0174
0175 ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);
0176 if (!ret)
0177 *cnop = (blkoff == start) ? start_cno :
0178 nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);
0179 return ret;
0180 }
0181
0182 static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
0183 __u64 cno)
0184 {
0185 return nilfs_mdt_delete_block(cpfile,
0186 nilfs_cpfile_get_blkoff(cpfile, cno));
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 int nilfs_cpfile_get_checkpoint(struct inode *cpfile,
0215 __u64 cno,
0216 int create,
0217 struct nilfs_checkpoint **cpp,
0218 struct buffer_head **bhp)
0219 {
0220 struct buffer_head *header_bh, *cp_bh;
0221 struct nilfs_cpfile_header *header;
0222 struct nilfs_checkpoint *cp;
0223 void *kaddr;
0224 int ret;
0225
0226 if (unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) ||
0227 (cno < nilfs_mdt_cno(cpfile) && create)))
0228 return -EINVAL;
0229
0230 down_write(&NILFS_MDT(cpfile)->mi_sem);
0231
0232 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
0233 if (ret < 0)
0234 goto out_sem;
0235 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh);
0236 if (ret < 0)
0237 goto out_header;
0238 kaddr = kmap(cp_bh->b_page);
0239 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
0240 if (nilfs_checkpoint_invalid(cp)) {
0241 if (!create) {
0242 kunmap(cp_bh->b_page);
0243 brelse(cp_bh);
0244 ret = -ENOENT;
0245 goto out_header;
0246 }
0247
0248 nilfs_checkpoint_clear_invalid(cp);
0249 if (!nilfs_cpfile_is_in_first(cpfile, cno))
0250 nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
0251 kaddr, 1);
0252 mark_buffer_dirty(cp_bh);
0253
0254 kaddr = kmap_atomic(header_bh->b_page);
0255 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
0256 kaddr);
0257 le64_add_cpu(&header->ch_ncheckpoints, 1);
0258 kunmap_atomic(kaddr);
0259 mark_buffer_dirty(header_bh);
0260 nilfs_mdt_mark_dirty(cpfile);
0261 }
0262
0263 if (cpp != NULL)
0264 *cpp = cp;
0265 *bhp = cp_bh;
0266
0267 out_header:
0268 brelse(header_bh);
0269
0270 out_sem:
0271 up_write(&NILFS_MDT(cpfile)->mi_sem);
0272 return ret;
0273 }
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno,
0286 struct buffer_head *bh)
0287 {
0288 kunmap(bh->b_page);
0289 brelse(bh);
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311 int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
0312 __u64 start,
0313 __u64 end)
0314 {
0315 struct buffer_head *header_bh, *cp_bh;
0316 struct nilfs_cpfile_header *header;
0317 struct nilfs_checkpoint *cp;
0318 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
0319 __u64 cno;
0320 void *kaddr;
0321 unsigned long tnicps;
0322 int ret, ncps, nicps, nss, count, i;
0323
0324 if (unlikely(start == 0 || start > end)) {
0325 nilfs_err(cpfile->i_sb,
0326 "cannot delete checkpoints: invalid range [%llu, %llu)",
0327 (unsigned long long)start, (unsigned long long)end);
0328 return -EINVAL;
0329 }
0330
0331 down_write(&NILFS_MDT(cpfile)->mi_sem);
0332
0333 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
0334 if (ret < 0)
0335 goto out_sem;
0336 tnicps = 0;
0337 nss = 0;
0338
0339 for (cno = start; cno < end; cno += ncps) {
0340 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
0341 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
0342 if (ret < 0) {
0343 if (ret != -ENOENT)
0344 break;
0345
0346 ret = 0;
0347 continue;
0348 }
0349
0350 kaddr = kmap_atomic(cp_bh->b_page);
0351 cp = nilfs_cpfile_block_get_checkpoint(
0352 cpfile, cno, cp_bh, kaddr);
0353 nicps = 0;
0354 for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
0355 if (nilfs_checkpoint_snapshot(cp)) {
0356 nss++;
0357 } else if (!nilfs_checkpoint_invalid(cp)) {
0358 nilfs_checkpoint_set_invalid(cp);
0359 nicps++;
0360 }
0361 }
0362 if (nicps > 0) {
0363 tnicps += nicps;
0364 mark_buffer_dirty(cp_bh);
0365 nilfs_mdt_mark_dirty(cpfile);
0366 if (!nilfs_cpfile_is_in_first(cpfile, cno)) {
0367 count =
0368 nilfs_cpfile_block_sub_valid_checkpoints(
0369 cpfile, cp_bh, kaddr, nicps);
0370 if (count == 0) {
0371
0372 kunmap_atomic(kaddr);
0373 brelse(cp_bh);
0374 ret =
0375 nilfs_cpfile_delete_checkpoint_block(
0376 cpfile, cno);
0377 if (ret == 0)
0378 continue;
0379 nilfs_err(cpfile->i_sb,
0380 "error %d deleting checkpoint block",
0381 ret);
0382 break;
0383 }
0384 }
0385 }
0386
0387 kunmap_atomic(kaddr);
0388 brelse(cp_bh);
0389 }
0390
0391 if (tnicps > 0) {
0392 kaddr = kmap_atomic(header_bh->b_page);
0393 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
0394 kaddr);
0395 le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);
0396 mark_buffer_dirty(header_bh);
0397 nilfs_mdt_mark_dirty(cpfile);
0398 kunmap_atomic(kaddr);
0399 }
0400
0401 brelse(header_bh);
0402 if (nss > 0)
0403 ret = -EBUSY;
0404
0405 out_sem:
0406 up_write(&NILFS_MDT(cpfile)->mi_sem);
0407 return ret;
0408 }
0409
0410 static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
0411 struct nilfs_checkpoint *cp,
0412 struct nilfs_cpinfo *ci)
0413 {
0414 ci->ci_flags = le32_to_cpu(cp->cp_flags);
0415 ci->ci_cno = le64_to_cpu(cp->cp_cno);
0416 ci->ci_create = le64_to_cpu(cp->cp_create);
0417 ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);
0418 ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);
0419 ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);
0420 ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
0421 }
0422
0423 static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
0424 void *buf, unsigned int cisz,
0425 size_t nci)
0426 {
0427 struct nilfs_checkpoint *cp;
0428 struct nilfs_cpinfo *ci = buf;
0429 struct buffer_head *bh;
0430 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
0431 __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
0432 void *kaddr;
0433 int n, ret;
0434 int ncps, i;
0435
0436 if (cno == 0)
0437 return -ENOENT;
0438 down_read(&NILFS_MDT(cpfile)->mi_sem);
0439
0440 for (n = 0; n < nci; cno += ncps) {
0441 ret = nilfs_cpfile_find_checkpoint_block(
0442 cpfile, cno, cur_cno - 1, &cno, &bh);
0443 if (ret < 0) {
0444 if (likely(ret == -ENOENT))
0445 break;
0446 goto out;
0447 }
0448 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
0449
0450 kaddr = kmap_atomic(bh->b_page);
0451 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
0452 for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
0453 if (!nilfs_checkpoint_invalid(cp)) {
0454 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
0455 ci);
0456 ci = (void *)ci + cisz;
0457 n++;
0458 }
0459 }
0460 kunmap_atomic(kaddr);
0461 brelse(bh);
0462 }
0463
0464 ret = n;
0465 if (n > 0) {
0466 ci = (void *)ci - cisz;
0467 *cnop = ci->ci_cno + 1;
0468 }
0469
0470 out:
0471 up_read(&NILFS_MDT(cpfile)->mi_sem);
0472 return ret;
0473 }
0474
0475 static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
0476 void *buf, unsigned int cisz,
0477 size_t nci)
0478 {
0479 struct buffer_head *bh;
0480 struct nilfs_cpfile_header *header;
0481 struct nilfs_checkpoint *cp;
0482 struct nilfs_cpinfo *ci = buf;
0483 __u64 curr = *cnop, next;
0484 unsigned long curr_blkoff, next_blkoff;
0485 void *kaddr;
0486 int n = 0, ret;
0487
0488 down_read(&NILFS_MDT(cpfile)->mi_sem);
0489
0490 if (curr == 0) {
0491 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
0492 if (ret < 0)
0493 goto out;
0494 kaddr = kmap_atomic(bh->b_page);
0495 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
0496 curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);
0497 kunmap_atomic(kaddr);
0498 brelse(bh);
0499 if (curr == 0) {
0500 ret = 0;
0501 goto out;
0502 }
0503 } else if (unlikely(curr == ~(__u64)0)) {
0504 ret = 0;
0505 goto out;
0506 }
0507
0508 curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
0509 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
0510 if (unlikely(ret < 0)) {
0511 if (ret == -ENOENT)
0512 ret = 0;
0513 goto out;
0514 }
0515 kaddr = kmap_atomic(bh->b_page);
0516 while (n < nci) {
0517 cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);
0518 curr = ~(__u64)0;
0519 if (unlikely(nilfs_checkpoint_invalid(cp) ||
0520 !nilfs_checkpoint_snapshot(cp)))
0521 break;
0522 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
0523 ci = (void *)ci + cisz;
0524 n++;
0525 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
0526 if (next == 0)
0527 break;
0528
0529 next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
0530 if (curr_blkoff != next_blkoff) {
0531 kunmap_atomic(kaddr);
0532 brelse(bh);
0533 ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
0534 0, &bh);
0535 if (unlikely(ret < 0)) {
0536 WARN_ON(ret == -ENOENT);
0537 goto out;
0538 }
0539 kaddr = kmap_atomic(bh->b_page);
0540 }
0541 curr = next;
0542 curr_blkoff = next_blkoff;
0543 }
0544 kunmap_atomic(kaddr);
0545 brelse(bh);
0546 *cnop = curr;
0547 ret = n;
0548
0549 out:
0550 up_read(&NILFS_MDT(cpfile)->mi_sem);
0551 return ret;
0552 }
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562 ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
0563 void *buf, unsigned int cisz, size_t nci)
0564 {
0565 switch (mode) {
0566 case NILFS_CHECKPOINT:
0567 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
0568 case NILFS_SNAPSHOT:
0569 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
0570 default:
0571 return -EINVAL;
0572 }
0573 }
0574
0575
0576
0577
0578
0579
0580 int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
0581 {
0582 struct nilfs_cpinfo ci;
0583 __u64 tcno = cno;
0584 ssize_t nci;
0585
0586 nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
0587 if (nci < 0)
0588 return nci;
0589 else if (nci == 0 || ci.ci_cno != cno)
0590 return -ENOENT;
0591 else if (nilfs_cpinfo_snapshot(&ci))
0592 return -EBUSY;
0593
0594 return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
0595 }
0596
0597 static struct nilfs_snapshot_list *
0598 nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile,
0599 __u64 cno,
0600 struct buffer_head *bh,
0601 void *kaddr)
0602 {
0603 struct nilfs_cpfile_header *header;
0604 struct nilfs_checkpoint *cp;
0605 struct nilfs_snapshot_list *list;
0606
0607 if (cno != 0) {
0608 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
0609 list = &cp->cp_snapshot_list;
0610 } else {
0611 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
0612 list = &header->ch_snapshot_list;
0613 }
0614 return list;
0615 }
0616
0617 static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
0618 {
0619 struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
0620 struct nilfs_cpfile_header *header;
0621 struct nilfs_checkpoint *cp;
0622 struct nilfs_snapshot_list *list;
0623 __u64 curr, prev;
0624 unsigned long curr_blkoff, prev_blkoff;
0625 void *kaddr;
0626 int ret;
0627
0628 if (cno == 0)
0629 return -ENOENT;
0630 down_write(&NILFS_MDT(cpfile)->mi_sem);
0631
0632 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
0633 if (ret < 0)
0634 goto out_sem;
0635 kaddr = kmap_atomic(cp_bh->b_page);
0636 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
0637 if (nilfs_checkpoint_invalid(cp)) {
0638 ret = -ENOENT;
0639 kunmap_atomic(kaddr);
0640 goto out_cp;
0641 }
0642 if (nilfs_checkpoint_snapshot(cp)) {
0643 ret = 0;
0644 kunmap_atomic(kaddr);
0645 goto out_cp;
0646 }
0647 kunmap_atomic(kaddr);
0648
0649 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
0650 if (ret < 0)
0651 goto out_cp;
0652 kaddr = kmap_atomic(header_bh->b_page);
0653 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
0654 list = &header->ch_snapshot_list;
0655 curr_bh = header_bh;
0656 get_bh(curr_bh);
0657 curr = 0;
0658 curr_blkoff = 0;
0659 prev = le64_to_cpu(list->ssl_prev);
0660 while (prev > cno) {
0661 prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
0662 curr = prev;
0663 if (curr_blkoff != prev_blkoff) {
0664 kunmap_atomic(kaddr);
0665 brelse(curr_bh);
0666 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
0667 0, &curr_bh);
0668 if (ret < 0)
0669 goto out_header;
0670 kaddr = kmap_atomic(curr_bh->b_page);
0671 }
0672 curr_blkoff = prev_blkoff;
0673 cp = nilfs_cpfile_block_get_checkpoint(
0674 cpfile, curr, curr_bh, kaddr);
0675 list = &cp->cp_snapshot_list;
0676 prev = le64_to_cpu(list->ssl_prev);
0677 }
0678 kunmap_atomic(kaddr);
0679
0680 if (prev != 0) {
0681 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
0682 &prev_bh);
0683 if (ret < 0)
0684 goto out_curr;
0685 } else {
0686 prev_bh = header_bh;
0687 get_bh(prev_bh);
0688 }
0689
0690 kaddr = kmap_atomic(curr_bh->b_page);
0691 list = nilfs_cpfile_block_get_snapshot_list(
0692 cpfile, curr, curr_bh, kaddr);
0693 list->ssl_prev = cpu_to_le64(cno);
0694 kunmap_atomic(kaddr);
0695
0696 kaddr = kmap_atomic(cp_bh->b_page);
0697 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
0698 cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
0699 cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
0700 nilfs_checkpoint_set_snapshot(cp);
0701 kunmap_atomic(kaddr);
0702
0703 kaddr = kmap_atomic(prev_bh->b_page);
0704 list = nilfs_cpfile_block_get_snapshot_list(
0705 cpfile, prev, prev_bh, kaddr);
0706 list->ssl_next = cpu_to_le64(cno);
0707 kunmap_atomic(kaddr);
0708
0709 kaddr = kmap_atomic(header_bh->b_page);
0710 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
0711 le64_add_cpu(&header->ch_nsnapshots, 1);
0712 kunmap_atomic(kaddr);
0713
0714 mark_buffer_dirty(prev_bh);
0715 mark_buffer_dirty(curr_bh);
0716 mark_buffer_dirty(cp_bh);
0717 mark_buffer_dirty(header_bh);
0718 nilfs_mdt_mark_dirty(cpfile);
0719
0720 brelse(prev_bh);
0721
0722 out_curr:
0723 brelse(curr_bh);
0724
0725 out_header:
0726 brelse(header_bh);
0727
0728 out_cp:
0729 brelse(cp_bh);
0730
0731 out_sem:
0732 up_write(&NILFS_MDT(cpfile)->mi_sem);
0733 return ret;
0734 }
0735
0736 static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
0737 {
0738 struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
0739 struct nilfs_cpfile_header *header;
0740 struct nilfs_checkpoint *cp;
0741 struct nilfs_snapshot_list *list;
0742 __u64 next, prev;
0743 void *kaddr;
0744 int ret;
0745
0746 if (cno == 0)
0747 return -ENOENT;
0748 down_write(&NILFS_MDT(cpfile)->mi_sem);
0749
0750 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
0751 if (ret < 0)
0752 goto out_sem;
0753 kaddr = kmap_atomic(cp_bh->b_page);
0754 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
0755 if (nilfs_checkpoint_invalid(cp)) {
0756 ret = -ENOENT;
0757 kunmap_atomic(kaddr);
0758 goto out_cp;
0759 }
0760 if (!nilfs_checkpoint_snapshot(cp)) {
0761 ret = 0;
0762 kunmap_atomic(kaddr);
0763 goto out_cp;
0764 }
0765
0766 list = &cp->cp_snapshot_list;
0767 next = le64_to_cpu(list->ssl_next);
0768 prev = le64_to_cpu(list->ssl_prev);
0769 kunmap_atomic(kaddr);
0770
0771 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
0772 if (ret < 0)
0773 goto out_cp;
0774 if (next != 0) {
0775 ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
0776 &next_bh);
0777 if (ret < 0)
0778 goto out_header;
0779 } else {
0780 next_bh = header_bh;
0781 get_bh(next_bh);
0782 }
0783 if (prev != 0) {
0784 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
0785 &prev_bh);
0786 if (ret < 0)
0787 goto out_next;
0788 } else {
0789 prev_bh = header_bh;
0790 get_bh(prev_bh);
0791 }
0792
0793 kaddr = kmap_atomic(next_bh->b_page);
0794 list = nilfs_cpfile_block_get_snapshot_list(
0795 cpfile, next, next_bh, kaddr);
0796 list->ssl_prev = cpu_to_le64(prev);
0797 kunmap_atomic(kaddr);
0798
0799 kaddr = kmap_atomic(prev_bh->b_page);
0800 list = nilfs_cpfile_block_get_snapshot_list(
0801 cpfile, prev, prev_bh, kaddr);
0802 list->ssl_next = cpu_to_le64(next);
0803 kunmap_atomic(kaddr);
0804
0805 kaddr = kmap_atomic(cp_bh->b_page);
0806 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
0807 cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
0808 cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
0809 nilfs_checkpoint_clear_snapshot(cp);
0810 kunmap_atomic(kaddr);
0811
0812 kaddr = kmap_atomic(header_bh->b_page);
0813 header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
0814 le64_add_cpu(&header->ch_nsnapshots, -1);
0815 kunmap_atomic(kaddr);
0816
0817 mark_buffer_dirty(next_bh);
0818 mark_buffer_dirty(prev_bh);
0819 mark_buffer_dirty(cp_bh);
0820 mark_buffer_dirty(header_bh);
0821 nilfs_mdt_mark_dirty(cpfile);
0822
0823 brelse(prev_bh);
0824
0825 out_next:
0826 brelse(next_bh);
0827
0828 out_header:
0829 brelse(header_bh);
0830
0831 out_cp:
0832 brelse(cp_bh);
0833
0834 out_sem:
0835 up_write(&NILFS_MDT(cpfile)->mi_sem);
0836 return ret;
0837 }
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856 int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
0857 {
0858 struct buffer_head *bh;
0859 struct nilfs_checkpoint *cp;
0860 void *kaddr;
0861 int ret;
0862
0863
0864
0865
0866
0867 if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))
0868 return -ENOENT;
0869 down_read(&NILFS_MDT(cpfile)->mi_sem);
0870
0871 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
0872 if (ret < 0)
0873 goto out;
0874 kaddr = kmap_atomic(bh->b_page);
0875 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
0876 if (nilfs_checkpoint_invalid(cp))
0877 ret = -ENOENT;
0878 else
0879 ret = nilfs_checkpoint_snapshot(cp);
0880 kunmap_atomic(kaddr);
0881 brelse(bh);
0882
0883 out:
0884 up_read(&NILFS_MDT(cpfile)->mi_sem);
0885 return ret;
0886 }
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906 int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
0907 {
0908 int ret;
0909
0910 switch (mode) {
0911 case NILFS_CHECKPOINT:
0912 if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
0913
0914
0915
0916
0917
0918
0919 ret = -EBUSY;
0920 else
0921 ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
0922 return ret;
0923 case NILFS_SNAPSHOT:
0924 return nilfs_cpfile_set_snapshot(cpfile, cno);
0925 default:
0926 return -EINVAL;
0927 }
0928 }
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945 int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
0946 {
0947 struct buffer_head *bh;
0948 struct nilfs_cpfile_header *header;
0949 void *kaddr;
0950 int ret;
0951
0952 down_read(&NILFS_MDT(cpfile)->mi_sem);
0953
0954 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
0955 if (ret < 0)
0956 goto out_sem;
0957 kaddr = kmap_atomic(bh->b_page);
0958 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
0959 cpstat->cs_cno = nilfs_mdt_cno(cpfile);
0960 cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);
0961 cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);
0962 kunmap_atomic(kaddr);
0963 brelse(bh);
0964
0965 out_sem:
0966 up_read(&NILFS_MDT(cpfile)->mi_sem);
0967 return ret;
0968 }
0969
0970
0971
0972
0973
0974
0975
0976
0977 int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
0978 struct nilfs_inode *raw_inode, struct inode **inodep)
0979 {
0980 struct inode *cpfile;
0981 int err;
0982
0983 if (cpsize > sb->s_blocksize) {
0984 nilfs_err(sb, "too large checkpoint size: %zu bytes", cpsize);
0985 return -EINVAL;
0986 } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
0987 nilfs_err(sb, "too small checkpoint size: %zu bytes", cpsize);
0988 return -EINVAL;
0989 }
0990
0991 cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
0992 if (unlikely(!cpfile))
0993 return -ENOMEM;
0994 if (!(cpfile->i_state & I_NEW))
0995 goto out;
0996
0997 err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
0998 if (err)
0999 goto failed;
1000
1001 nilfs_mdt_set_entry_size(cpfile, cpsize,
1002 sizeof(struct nilfs_cpfile_header));
1003
1004 err = nilfs_read_inode_common(cpfile, raw_inode);
1005 if (err)
1006 goto failed;
1007
1008 unlock_new_inode(cpfile);
1009 out:
1010 *inodep = cpfile;
1011 return 0;
1012 failed:
1013 iget_failed(cpfile);
1014 return err;
1015 }