diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-05-04 12:23:58 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-05-10 09:21:46 -0400 |
commit | 4e33f9eab07e985282fece4121066c2db1d332ed (patch) | |
tree | 08161cabc013f0543d65d9c9ed63689f9f68803d /fs/nilfs2/sufile.c | |
parent | 78eb64c2479e0f408b725c3c8e1cdf557857af48 (diff) |
nilfs2: implement resize ioctl
This adds resize ioctl which makes online resize possible.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/sufile.c')
-rw-r--r-- | fs/nilfs2/sufile.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 22f2e6ece1be..37b9631cc016 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -722,6 +722,73 @@ out: | |||
722 | } | 722 | } |
723 | 723 | ||
724 | /** | 724 | /** |
725 | * nilfs_sufile_resize - resize segment array | ||
726 | * @sufile: inode of segment usage file | ||
727 | * @newnsegs: new number of segments | ||
728 | * | ||
729 | * Return Value: On success, 0 is returned. On error, one of the | ||
730 | * following negative error codes is returned. | ||
731 | * | ||
732 | * %-EIO - I/O error. | ||
733 | * | ||
734 | * %-ENOMEM - Insufficient amount of memory available. | ||
735 | * | ||
736 | * %-ENOSPC - Enough free space is not left for shrinking | ||
737 | * | ||
738 | * %-EBUSY - Dirty or active segments exist in the region to be truncated | ||
739 | */ | ||
740 | int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs) | ||
741 | { | ||
742 | struct the_nilfs *nilfs = sufile->i_sb->s_fs_info; | ||
743 | struct buffer_head *header_bh; | ||
744 | struct nilfs_sufile_header *header; | ||
745 | struct nilfs_sufile_info *sui = NILFS_SUI(sufile); | ||
746 | void *kaddr; | ||
747 | unsigned long nsegs, nrsvsegs; | ||
748 | int ret = 0; | ||
749 | |||
750 | down_write(&NILFS_MDT(sufile)->mi_sem); | ||
751 | |||
752 | nsegs = nilfs_sufile_get_nsegments(sufile); | ||
753 | if (nsegs == newnsegs) | ||
754 | goto out; | ||
755 | |||
756 | ret = -ENOSPC; | ||
757 | nrsvsegs = nilfs_nrsvsegs(nilfs, newnsegs); | ||
758 | if (newnsegs < nsegs && nsegs - newnsegs + nrsvsegs > sui->ncleansegs) | ||
759 | goto out; | ||
760 | |||
761 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | ||
762 | if (ret < 0) | ||
763 | goto out; | ||
764 | |||
765 | if (newnsegs > nsegs) { | ||
766 | sui->ncleansegs += newnsegs - nsegs; | ||
767 | } else /* newnsegs < nsegs */ { | ||
768 | ret = nilfs_sufile_truncate_range(sufile, newnsegs, nsegs - 1); | ||
769 | if (ret < 0) | ||
770 | goto out_header; | ||
771 | |||
772 | sui->ncleansegs -= nsegs - newnsegs; | ||
773 | } | ||
774 | |||
775 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | ||
776 | header = kaddr + bh_offset(header_bh); | ||
777 | header->sh_ncleansegs = cpu_to_le64(sui->ncleansegs); | ||
778 | kunmap_atomic(kaddr, KM_USER0); | ||
779 | |||
780 | nilfs_mdt_mark_buffer_dirty(header_bh); | ||
781 | nilfs_mdt_mark_dirty(sufile); | ||
782 | nilfs_set_nsegments(nilfs, newnsegs); | ||
783 | |||
784 | out_header: | ||
785 | brelse(header_bh); | ||
786 | out: | ||
787 | up_write(&NILFS_MDT(sufile)->mi_sem); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | /** | ||
725 | * nilfs_sufile_get_suinfo - | 792 | * nilfs_sufile_get_suinfo - |
726 | * @sufile: inode of segment usage file | 793 | * @sufile: inode of segment usage file |
727 | * @segnum: segment number to start looking | 794 | * @segnum: segment number to start looking |