diff options
Diffstat (limited to 'fs/gfs2/file.c')
-rw-r--r-- | fs/gfs2/file.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index fca6689e12e6..7cfdcb913363 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/gfs2_ondisk.h> | 20 | #include <linux/gfs2_ondisk.h> |
21 | #include <linux/ext2_fs.h> | 21 | #include <linux/ext2_fs.h> |
22 | #include <linux/falloc.h> | ||
23 | #include <linux/swap.h> | ||
22 | #include <linux/crc32.h> | 24 | #include <linux/crc32.h> |
23 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
24 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
@@ -610,6 +612,260 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
610 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | 612 | return generic_file_aio_write(iocb, iov, nr_segs, pos); |
611 | } | 613 | } |
612 | 614 | ||
615 | static void empty_write_end(struct page *page, unsigned from, | ||
616 | unsigned to) | ||
617 | { | ||
618 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | ||
619 | |||
620 | page_zero_new_buffers(page, from, to); | ||
621 | flush_dcache_page(page); | ||
622 | mark_page_accessed(page); | ||
623 | |||
624 | if (!gfs2_is_writeback(ip)) | ||
625 | gfs2_page_add_databufs(ip, page, from, to); | ||
626 | |||
627 | block_commit_write(page, from, to); | ||
628 | } | ||
629 | |||
630 | static int write_empty_blocks(struct page *page, unsigned from, unsigned to) | ||
631 | { | ||
632 | unsigned start, end, next; | ||
633 | struct buffer_head *bh, *head; | ||
634 | int error; | ||
635 | |||
636 | if (!page_has_buffers(page)) { | ||
637 | error = __block_write_begin(page, from, to - from, gfs2_block_map); | ||
638 | if (unlikely(error)) | ||
639 | return error; | ||
640 | |||
641 | empty_write_end(page, from, to); | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | bh = head = page_buffers(page); | ||
646 | next = end = 0; | ||
647 | while (next < from) { | ||
648 | next += bh->b_size; | ||
649 | bh = bh->b_this_page; | ||
650 | } | ||
651 | start = next; | ||
652 | do { | ||
653 | next += bh->b_size; | ||
654 | if (buffer_mapped(bh)) { | ||
655 | if (end) { | ||
656 | error = __block_write_begin(page, start, end - start, | ||
657 | gfs2_block_map); | ||
658 | if (unlikely(error)) | ||
659 | return error; | ||
660 | empty_write_end(page, start, end); | ||
661 | end = 0; | ||
662 | } | ||
663 | start = next; | ||
664 | } | ||
665 | else | ||
666 | end = next; | ||
667 | bh = bh->b_this_page; | ||
668 | } while (next < to); | ||
669 | |||
670 | if (end) { | ||
671 | error = __block_write_begin(page, start, end - start, gfs2_block_map); | ||
672 | if (unlikely(error)) | ||
673 | return error; | ||
674 | empty_write_end(page, start, end); | ||
675 | } | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, | ||
681 | int mode) | ||
682 | { | ||
683 | struct gfs2_inode *ip = GFS2_I(inode); | ||
684 | struct buffer_head *dibh; | ||
685 | int error; | ||
686 | u64 start = offset >> PAGE_CACHE_SHIFT; | ||
687 | unsigned int start_offset = offset & ~PAGE_CACHE_MASK; | ||
688 | u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT; | ||
689 | pgoff_t curr; | ||
690 | struct page *page; | ||
691 | unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK; | ||
692 | unsigned int from, to; | ||
693 | |||
694 | if (!end_offset) | ||
695 | end_offset = PAGE_CACHE_SIZE; | ||
696 | |||
697 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
698 | if (unlikely(error)) | ||
699 | goto out; | ||
700 | |||
701 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
702 | |||
703 | if (gfs2_is_stuffed(ip)) { | ||
704 | error = gfs2_unstuff_dinode(ip, NULL); | ||
705 | if (unlikely(error)) | ||
706 | goto out; | ||
707 | } | ||
708 | |||
709 | curr = start; | ||
710 | offset = start << PAGE_CACHE_SHIFT; | ||
711 | from = start_offset; | ||
712 | to = PAGE_CACHE_SIZE; | ||
713 | while (curr <= end) { | ||
714 | page = grab_cache_page_write_begin(inode->i_mapping, curr, | ||
715 | AOP_FLAG_NOFS); | ||
716 | if (unlikely(!page)) { | ||
717 | error = -ENOMEM; | ||
718 | goto out; | ||
719 | } | ||
720 | |||
721 | if (curr == end) | ||
722 | to = end_offset; | ||
723 | error = write_empty_blocks(page, from, to); | ||
724 | if (!error && offset + to > inode->i_size && | ||
725 | !(mode & FALLOC_FL_KEEP_SIZE)) { | ||
726 | i_size_write(inode, offset + to); | ||
727 | } | ||
728 | unlock_page(page); | ||
729 | page_cache_release(page); | ||
730 | if (error) | ||
731 | goto out; | ||
732 | curr++; | ||
733 | offset += PAGE_CACHE_SIZE; | ||
734 | from = 0; | ||
735 | } | ||
736 | |||
737 | gfs2_dinode_out(ip, dibh->b_data); | ||
738 | mark_inode_dirty(inode); | ||
739 | |||
740 | brelse(dibh); | ||
741 | |||
742 | out: | ||
743 | return error; | ||
744 | } | ||
745 | |||
746 | static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len, | ||
747 | unsigned int *data_blocks, unsigned int *ind_blocks) | ||
748 | { | ||
749 | const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
750 | unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone; | ||
751 | unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1); | ||
752 | |||
753 | for (tmp = max_data; tmp > sdp->sd_diptrs;) { | ||
754 | tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs); | ||
755 | max_data -= tmp; | ||
756 | } | ||
757 | /* This calculation isn't the exact reverse of gfs2_write_calc_reserve, | ||
758 | so it might end up with fewer data blocks */ | ||
759 | if (max_data <= *data_blocks) | ||
760 | return; | ||
761 | *data_blocks = max_data; | ||
762 | *ind_blocks = max_blocks - max_data; | ||
763 | *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift; | ||
764 | if (*len > max) { | ||
765 | *len = max; | ||
766 | gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static long gfs2_fallocate(struct file *file, int mode, loff_t offset, | ||
771 | loff_t len) | ||
772 | { | ||
773 | struct inode *inode = file->f_path.dentry->d_inode; | ||
774 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
775 | struct gfs2_inode *ip = GFS2_I(inode); | ||
776 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; | ||
777 | loff_t bytes, max_bytes; | ||
778 | struct gfs2_alloc *al; | ||
779 | int error; | ||
780 | loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; | ||
781 | next = (next + 1) << sdp->sd_sb.sb_bsize_shift; | ||
782 | |||
783 | /* We only support the FALLOC_FL_KEEP_SIZE mode */ | ||
784 | if (mode & ~FALLOC_FL_KEEP_SIZE) | ||
785 | return -EOPNOTSUPP; | ||
786 | |||
787 | offset = (offset >> sdp->sd_sb.sb_bsize_shift) << | ||
788 | sdp->sd_sb.sb_bsize_shift; | ||
789 | |||
790 | len = next - offset; | ||
791 | bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; | ||
792 | if (!bytes) | ||
793 | bytes = UINT_MAX; | ||
794 | |||
795 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); | ||
796 | error = gfs2_glock_nq(&ip->i_gh); | ||
797 | if (unlikely(error)) | ||
798 | goto out_uninit; | ||
799 | |||
800 | if (!gfs2_write_alloc_required(ip, offset, len)) | ||
801 | goto out_unlock; | ||
802 | |||
803 | while (len > 0) { | ||
804 | if (len < bytes) | ||
805 | bytes = len; | ||
806 | al = gfs2_alloc_get(ip); | ||
807 | if (!al) { | ||
808 | error = -ENOMEM; | ||
809 | goto out_unlock; | ||
810 | } | ||
811 | |||
812 | error = gfs2_quota_lock_check(ip); | ||
813 | if (error) | ||
814 | goto out_alloc_put; | ||
815 | |||
816 | retry: | ||
817 | gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks); | ||
818 | |||
819 | al->al_requested = data_blocks + ind_blocks; | ||
820 | error = gfs2_inplace_reserve(ip); | ||
821 | if (error) { | ||
822 | if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { | ||
823 | bytes >>= 1; | ||
824 | goto retry; | ||
825 | } | ||
826 | goto out_qunlock; | ||
827 | } | ||
828 | max_bytes = bytes; | ||
829 | calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks); | ||
830 | al->al_requested = data_blocks + ind_blocks; | ||
831 | |||
832 | rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + | ||
833 | RES_RG_HDR + gfs2_rg_blocks(al); | ||
834 | if (gfs2_is_jdata(ip)) | ||
835 | rblocks += data_blocks ? data_blocks : 1; | ||
836 | |||
837 | error = gfs2_trans_begin(sdp, rblocks, | ||
838 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); | ||
839 | if (error) | ||
840 | goto out_trans_fail; | ||
841 | |||
842 | error = fallocate_chunk(inode, offset, max_bytes, mode); | ||
843 | gfs2_trans_end(sdp); | ||
844 | |||
845 | if (error) | ||
846 | goto out_trans_fail; | ||
847 | |||
848 | len -= max_bytes; | ||
849 | offset += max_bytes; | ||
850 | gfs2_inplace_release(ip); | ||
851 | gfs2_quota_unlock(ip); | ||
852 | gfs2_alloc_put(ip); | ||
853 | } | ||
854 | goto out_unlock; | ||
855 | |||
856 | out_trans_fail: | ||
857 | gfs2_inplace_release(ip); | ||
858 | out_qunlock: | ||
859 | gfs2_quota_unlock(ip); | ||
860 | out_alloc_put: | ||
861 | gfs2_alloc_put(ip); | ||
862 | out_unlock: | ||
863 | gfs2_glock_dq(&ip->i_gh); | ||
864 | out_uninit: | ||
865 | gfs2_holder_uninit(&ip->i_gh); | ||
866 | return error; | ||
867 | } | ||
868 | |||
613 | #ifdef CONFIG_GFS2_FS_LOCKING_DLM | 869 | #ifdef CONFIG_GFS2_FS_LOCKING_DLM |
614 | 870 | ||
615 | /** | 871 | /** |
@@ -765,6 +1021,7 @@ const struct file_operations gfs2_file_fops = { | |||
765 | .splice_read = generic_file_splice_read, | 1021 | .splice_read = generic_file_splice_read, |
766 | .splice_write = generic_file_splice_write, | 1022 | .splice_write = generic_file_splice_write, |
767 | .setlease = gfs2_setlease, | 1023 | .setlease = gfs2_setlease, |
1024 | .fallocate = gfs2_fallocate, | ||
768 | }; | 1025 | }; |
769 | 1026 | ||
770 | const struct file_operations gfs2_dir_fops = { | 1027 | const struct file_operations gfs2_dir_fops = { |
@@ -794,6 +1051,7 @@ const struct file_operations gfs2_file_fops_nolock = { | |||
794 | .splice_read = generic_file_splice_read, | 1051 | .splice_read = generic_file_splice_read, |
795 | .splice_write = generic_file_splice_write, | 1052 | .splice_write = generic_file_splice_write, |
796 | .setlease = generic_setlease, | 1053 | .setlease = generic_setlease, |
1054 | .fallocate = gfs2_fallocate, | ||
797 | }; | 1055 | }; |
798 | 1056 | ||
799 | const struct file_operations gfs2_dir_fops_nolock = { | 1057 | const struct file_operations gfs2_dir_fops_nolock = { |