diff options
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/sufile.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index f4374df00ad5..22f2e6ece1be 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -98,6 +98,13 @@ nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum, | |||
98 | create, NULL, bhp); | 98 | create, NULL, bhp); |
99 | } | 99 | } |
100 | 100 | ||
101 | static int nilfs_sufile_delete_segment_usage_block(struct inode *sufile, | ||
102 | __u64 segnum) | ||
103 | { | ||
104 | return nilfs_mdt_delete_block(sufile, | ||
105 | nilfs_sufile_get_blkoff(sufile, segnum)); | ||
106 | } | ||
107 | |||
101 | static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, | 108 | static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, |
102 | u64 ncleanadd, u64 ndirtyadd) | 109 | u64 ncleanadd, u64 ndirtyadd) |
103 | { | 110 | { |
@@ -610,6 +617,111 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, | |||
610 | } | 617 | } |
611 | 618 | ||
612 | /** | 619 | /** |
620 | * nilfs_sufile_truncate_range - truncate range of segment array | ||
621 | * @sufile: inode of segment usage file | ||
622 | * @start: start segment number (inclusive) | ||
623 | * @end: end segment number (inclusive) | ||
624 | * | ||
625 | * Return Value: On success, 0 is returned. On error, one of the | ||
626 | * following negative error codes is returned. | ||
627 | * | ||
628 | * %-EIO - I/O error. | ||
629 | * | ||
630 | * %-ENOMEM - Insufficient amount of memory available. | ||
631 | * | ||
632 | * %-EINVAL - Invalid number of segments specified | ||
633 | * | ||
634 | * %-EBUSY - Dirty or active segments are present in the range | ||
635 | */ | ||
636 | static int nilfs_sufile_truncate_range(struct inode *sufile, | ||
637 | __u64 start, __u64 end) | ||
638 | { | ||
639 | struct the_nilfs *nilfs = sufile->i_sb->s_fs_info; | ||
640 | struct buffer_head *header_bh; | ||
641 | struct buffer_head *su_bh; | ||
642 | struct nilfs_segment_usage *su, *su2; | ||
643 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; | ||
644 | unsigned long segusages_per_block; | ||
645 | unsigned long nsegs, ncleaned; | ||
646 | __u64 segnum; | ||
647 | void *kaddr; | ||
648 | ssize_t n, nc; | ||
649 | int ret; | ||
650 | int j; | ||
651 | |||
652 | nsegs = nilfs_sufile_get_nsegments(sufile); | ||
653 | |||
654 | ret = -EINVAL; | ||
655 | if (start > end || start >= nsegs) | ||
656 | goto out; | ||
657 | |||
658 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | ||
659 | if (ret < 0) | ||
660 | goto out; | ||
661 | |||
662 | segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile); | ||
663 | ncleaned = 0; | ||
664 | |||
665 | for (segnum = start; segnum <= end; segnum += n) { | ||
666 | n = min_t(unsigned long, | ||
667 | segusages_per_block - | ||
668 | nilfs_sufile_get_offset(sufile, segnum), | ||
669 | end - segnum + 1); | ||
670 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, | ||
671 | &su_bh); | ||
672 | if (ret < 0) { | ||
673 | if (ret != -ENOENT) | ||
674 | goto out_header; | ||
675 | /* hole */ | ||
676 | continue; | ||
677 | } | ||
678 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | ||
679 | su = nilfs_sufile_block_get_segment_usage( | ||
680 | sufile, segnum, su_bh, kaddr); | ||
681 | su2 = su; | ||
682 | for (j = 0; j < n; j++, su = (void *)su + susz) { | ||
683 | if ((le32_to_cpu(su->su_flags) & | ||
684 | ~(1UL << NILFS_SEGMENT_USAGE_ERROR)) || | ||
685 | nilfs_segment_is_active(nilfs, segnum + j)) { | ||
686 | ret = -EBUSY; | ||
687 | kunmap_atomic(kaddr, KM_USER0); | ||
688 | brelse(su_bh); | ||
689 | goto out_header; | ||
690 | } | ||
691 | } | ||
692 | nc = 0; | ||
693 | for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) { | ||
694 | if (nilfs_segment_usage_error(su)) { | ||
695 | nilfs_segment_usage_set_clean(su); | ||
696 | nc++; | ||
697 | } | ||
698 | } | ||
699 | kunmap_atomic(kaddr, KM_USER0); | ||
700 | if (nc > 0) { | ||
701 | nilfs_mdt_mark_buffer_dirty(su_bh); | ||
702 | ncleaned += nc; | ||
703 | } | ||
704 | brelse(su_bh); | ||
705 | |||
706 | if (n == segusages_per_block) { | ||
707 | /* make hole */ | ||
708 | nilfs_sufile_delete_segment_usage_block(sufile, segnum); | ||
709 | } | ||
710 | } | ||
711 | ret = 0; | ||
712 | |||
713 | out_header: | ||
714 | if (ncleaned > 0) { | ||
715 | NILFS_SUI(sufile)->ncleansegs += ncleaned; | ||
716 | nilfs_sufile_mod_counter(header_bh, ncleaned, 0); | ||
717 | nilfs_mdt_mark_dirty(sufile); | ||
718 | } | ||
719 | brelse(header_bh); | ||
720 | out: | ||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | /** | ||
613 | * nilfs_sufile_get_suinfo - | 725 | * nilfs_sufile_get_suinfo - |
614 | * @sufile: inode of segment usage file | 726 | * @sufile: inode of segment usage file |
615 | * @segnum: segment number to start looking | 727 | * @segnum: segment number to start looking |