aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/cpfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nilfs2/cpfile.c')
-rw-r--r--fs/nilfs2/cpfile.c47
1 files changed, 23 insertions, 24 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index cadd36b14d07..7d49813f66d6 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -295,10 +295,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
295 return -EINVAL; 295 return -EINVAL;
296 } 296 }
297 297
298 /* cannot delete the latest checkpoint */
299 if (start == nilfs_mdt_cno(cpfile) - 1)
300 return -EPERM;
301
302 down_write(&NILFS_MDT(cpfile)->mi_sem); 298 down_write(&NILFS_MDT(cpfile)->mi_sem);
303 299
304 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); 300 ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
@@ -384,9 +380,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
384} 380}
385 381
386static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, 382static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
387 struct nilfs_cpinfo *ci, size_t nci) 383 void *buf, unsigned cisz, size_t nci)
388{ 384{
389 struct nilfs_checkpoint *cp; 385 struct nilfs_checkpoint *cp;
386 struct nilfs_cpinfo *ci = buf;
390 struct buffer_head *bh; 387 struct buffer_head *bh;
391 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; 388 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
392 __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; 389 __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
@@ -410,17 +407,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
410 kaddr = kmap_atomic(bh->b_page, KM_USER0); 407 kaddr = kmap_atomic(bh->b_page, KM_USER0);
411 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); 408 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
412 for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { 409 for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
413 if (!nilfs_checkpoint_invalid(cp)) 410 if (!nilfs_checkpoint_invalid(cp)) {
414 nilfs_cpfile_checkpoint_to_cpinfo( 411 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
415 cpfile, cp, &ci[n++]); 412 ci);
413 ci = (void *)ci + cisz;
414 n++;
415 }
416 } 416 }
417 kunmap_atomic(kaddr, KM_USER0); 417 kunmap_atomic(kaddr, KM_USER0);
418 brelse(bh); 418 brelse(bh);
419 } 419 }
420 420
421 ret = n; 421 ret = n;
422 if (n > 0) 422 if (n > 0) {
423 *cnop = ci[n - 1].ci_cno + 1; 423 ci = (void *)ci - cisz;
424 *cnop = ci->ci_cno + 1;
425 }
424 426
425 out: 427 out:
426 up_read(&NILFS_MDT(cpfile)->mi_sem); 428 up_read(&NILFS_MDT(cpfile)->mi_sem);
@@ -428,11 +430,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
428} 430}
429 431
430static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, 432static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
431 struct nilfs_cpinfo *ci, size_t nci) 433 void *buf, unsigned cisz, size_t nci)
432{ 434{
433 struct buffer_head *bh; 435 struct buffer_head *bh;
434 struct nilfs_cpfile_header *header; 436 struct nilfs_cpfile_header *header;
435 struct nilfs_checkpoint *cp; 437 struct nilfs_checkpoint *cp;
438 struct nilfs_cpinfo *ci = buf;
436 __u64 curr = *cnop, next; 439 __u64 curr = *cnop, next;
437 unsigned long curr_blkoff, next_blkoff; 440 unsigned long curr_blkoff, next_blkoff;
438 void *kaddr; 441 void *kaddr;
@@ -472,7 +475,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
472 if (unlikely(nilfs_checkpoint_invalid(cp) || 475 if (unlikely(nilfs_checkpoint_invalid(cp) ||
473 !nilfs_checkpoint_snapshot(cp))) 476 !nilfs_checkpoint_snapshot(cp)))
474 break; 477 break;
475 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); 478 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
479 ci = (void *)ci + cisz;
480 n++;
476 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); 481 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
477 if (next == 0) 482 if (next == 0)
478 break; /* reach end of the snapshot list */ 483 break; /* reach end of the snapshot list */
@@ -511,13 +516,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
511 */ 516 */
512 517
513ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, 518ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
514 struct nilfs_cpinfo *ci, size_t nci) 519 void *buf, unsigned cisz, size_t nci)
515{ 520{
516 switch (mode) { 521 switch (mode) {
517 case NILFS_CHECKPOINT: 522 case NILFS_CHECKPOINT:
518 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); 523 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
519 case NILFS_SNAPSHOT: 524 case NILFS_SNAPSHOT:
520 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); 525 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
521 default: 526 default:
522 return -EINVAL; 527 return -EINVAL;
523 } 528 }
@@ -533,20 +538,14 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
533 struct nilfs_cpinfo ci; 538 struct nilfs_cpinfo ci;
534 __u64 tcno = cno; 539 __u64 tcno = cno;
535 ssize_t nci; 540 ssize_t nci;
536 int ret;
537 541
538 nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); 542 nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
539 if (nci < 0) 543 if (nci < 0)
540 return nci; 544 return nci;
541 else if (nci == 0 || ci.ci_cno != cno) 545 else if (nci == 0 || ci.ci_cno != cno)
542 return -ENOENT; 546 return -ENOENT;
543 547 else if (nilfs_cpinfo_snapshot(&ci))
544 /* cannot delete the latest checkpoint nor snapshots */ 548 return -EBUSY;
545 ret = nilfs_cpinfo_snapshot(&ci);
546 if (ret < 0)
547 return ret;
548 else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1)
549 return -EPERM;
550 549
551 return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); 550 return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
552} 551}