diff options
Diffstat (limited to 'fs/ocfs2/file.c')
| -rw-r--r-- | fs/ocfs2/file.c | 86 |
1 files changed, 62 insertions, 24 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 581eb451a41a..a9559c874530 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -613,7 +613,8 @@ leave: | |||
| 613 | 613 | ||
| 614 | /* Some parts of this taken from generic_cont_expand, which turned out | 614 | /* Some parts of this taken from generic_cont_expand, which turned out |
| 615 | * to be too fragile to do exactly what we need without us having to | 615 | * to be too fragile to do exactly what we need without us having to |
| 616 | * worry about recursive locking in ->commit_write(). */ | 616 | * worry about recursive locking in ->prepare_write() and |
| 617 | * ->commit_write(). */ | ||
| 617 | static int ocfs2_write_zero_page(struct inode *inode, | 618 | static int ocfs2_write_zero_page(struct inode *inode, |
| 618 | u64 size) | 619 | u64 size) |
| 619 | { | 620 | { |
| @@ -641,7 +642,7 @@ static int ocfs2_write_zero_page(struct inode *inode, | |||
| 641 | goto out; | 642 | goto out; |
| 642 | } | 643 | } |
| 643 | 644 | ||
| 644 | ret = ocfs2_prepare_write(NULL, page, offset, offset); | 645 | ret = ocfs2_prepare_write_nolock(inode, page, offset, offset); |
| 645 | if (ret < 0) { | 646 | if (ret < 0) { |
| 646 | mlog_errno(ret); | 647 | mlog_errno(ret); |
| 647 | goto out_unlock; | 648 | goto out_unlock; |
| @@ -695,13 +696,26 @@ out: | |||
| 695 | return ret; | 696 | return ret; |
| 696 | } | 697 | } |
| 697 | 698 | ||
| 699 | /* | ||
| 700 | * A tail_to_skip value > 0 indicates that we're being called from | ||
| 701 | * ocfs2_file_aio_write(). This has the following implications: | ||
| 702 | * | ||
| 703 | * - we don't want to update i_size | ||
| 704 | * - di_bh will be NULL, which is fine because it's only used in the | ||
| 705 | * case where we want to update i_size. | ||
| 706 | * - ocfs2_zero_extend() will then only be filling the hole created | ||
| 707 | * between i_size and the start of the write. | ||
| 708 | */ | ||
| 698 | static int ocfs2_extend_file(struct inode *inode, | 709 | static int ocfs2_extend_file(struct inode *inode, |
| 699 | struct buffer_head *di_bh, | 710 | struct buffer_head *di_bh, |
| 700 | u64 new_i_size) | 711 | u64 new_i_size, |
| 712 | size_t tail_to_skip) | ||
| 701 | { | 713 | { |
| 702 | int ret = 0; | 714 | int ret = 0; |
| 703 | u32 clusters_to_add; | 715 | u32 clusters_to_add; |
| 704 | 716 | ||
| 717 | BUG_ON(!tail_to_skip && !di_bh); | ||
| 718 | |||
| 705 | /* setattr sometimes calls us like this. */ | 719 | /* setattr sometimes calls us like this. */ |
| 706 | if (new_i_size == 0) | 720 | if (new_i_size == 0) |
| 707 | goto out; | 721 | goto out; |
| @@ -714,27 +728,44 @@ static int ocfs2_extend_file(struct inode *inode, | |||
| 714 | OCFS2_I(inode)->ip_clusters; | 728 | OCFS2_I(inode)->ip_clusters; |
| 715 | 729 | ||
| 716 | if (clusters_to_add) { | 730 | if (clusters_to_add) { |
| 717 | ret = ocfs2_extend_allocation(inode, clusters_to_add); | 731 | /* |
| 732 | * protect the pages that ocfs2_zero_extend is going to | ||
| 733 | * be pulling into the page cache.. we do this before the | ||
| 734 | * metadata extend so that we don't get into the situation | ||
| 735 | * where we've extended the metadata but can't get the data | ||
| 736 | * lock to zero. | ||
| 737 | */ | ||
| 738 | ret = ocfs2_data_lock(inode, 1); | ||
| 718 | if (ret < 0) { | 739 | if (ret < 0) { |
| 719 | mlog_errno(ret); | 740 | mlog_errno(ret); |
| 720 | goto out; | 741 | goto out; |
| 721 | } | 742 | } |
| 722 | 743 | ||
| 723 | ret = ocfs2_zero_extend(inode, new_i_size); | 744 | ret = ocfs2_extend_allocation(inode, clusters_to_add); |
| 724 | if (ret < 0) { | 745 | if (ret < 0) { |
| 725 | mlog_errno(ret); | 746 | mlog_errno(ret); |
| 726 | goto out; | 747 | goto out_unlock; |
| 727 | } | 748 | } |
| 728 | } | ||
| 729 | 749 | ||
| 730 | /* No allocation required, we just use this helper to | 750 | ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip); |
| 731 | * do a trivial update of i_size. */ | 751 | if (ret < 0) { |
| 732 | ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); | 752 | mlog_errno(ret); |
| 733 | if (ret < 0) { | 753 | goto out_unlock; |
| 734 | mlog_errno(ret); | 754 | } |
| 735 | goto out; | 755 | } |
| 756 | |||
| 757 | if (!tail_to_skip) { | ||
| 758 | /* We're being called from ocfs2_setattr() which wants | ||
| 759 | * us to update i_size */ | ||
| 760 | ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); | ||
| 761 | if (ret < 0) | ||
| 762 | mlog_errno(ret); | ||
| 736 | } | 763 | } |
| 737 | 764 | ||
| 765 | out_unlock: | ||
| 766 | if (clusters_to_add) /* this is the only case in which we lock */ | ||
| 767 | ocfs2_data_unlock(inode, 1); | ||
| 768 | |||
| 738 | out: | 769 | out: |
| 739 | return ret; | 770 | return ret; |
| 740 | } | 771 | } |
| @@ -793,7 +824,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 793 | if (i_size_read(inode) > attr->ia_size) | 824 | if (i_size_read(inode) > attr->ia_size) |
| 794 | status = ocfs2_truncate_file(inode, bh, attr->ia_size); | 825 | status = ocfs2_truncate_file(inode, bh, attr->ia_size); |
| 795 | else | 826 | else |
| 796 | status = ocfs2_extend_file(inode, bh, attr->ia_size); | 827 | status = ocfs2_extend_file(inode, bh, attr->ia_size, 0); |
| 797 | if (status < 0) { | 828 | if (status < 0) { |
| 798 | if (status != -ENOSPC) | 829 | if (status != -ENOSPC) |
| 799 | mlog_errno(status); | 830 | mlog_errno(status); |
| @@ -1049,21 +1080,12 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, | |||
| 1049 | if (!clusters) | 1080 | if (!clusters) |
| 1050 | break; | 1081 | break; |
| 1051 | 1082 | ||
| 1052 | ret = ocfs2_extend_allocation(inode, clusters); | 1083 | ret = ocfs2_extend_file(inode, NULL, newsize, count); |
| 1053 | if (ret < 0) { | 1084 | if (ret < 0) { |
| 1054 | if (ret != -ENOSPC) | 1085 | if (ret != -ENOSPC) |
| 1055 | mlog_errno(ret); | 1086 | mlog_errno(ret); |
| 1056 | goto out; | 1087 | goto out; |
| 1057 | } | 1088 | } |
| 1058 | |||
| 1059 | /* Fill any holes which would've been created by this | ||
| 1060 | * write. If we're O_APPEND, this will wind up | ||
| 1061 | * (correctly) being a noop. */ | ||
| 1062 | ret = ocfs2_zero_extend(inode, (u64) newsize - count); | ||
| 1063 | if (ret < 0) { | ||
| 1064 | mlog_errno(ret); | ||
| 1065 | goto out; | ||
| 1066 | } | ||
| 1067 | break; | 1089 | break; |
| 1068 | } | 1090 | } |
| 1069 | 1091 | ||
| @@ -1146,6 +1168,22 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
| 1146 | ocfs2_iocb_set_rw_locked(iocb); | 1168 | ocfs2_iocb_set_rw_locked(iocb); |
| 1147 | } | 1169 | } |
| 1148 | 1170 | ||
| 1171 | /* | ||
| 1172 | * We're fine letting folks race truncates and extending | ||
| 1173 | * writes with read across the cluster, just like they can | ||
| 1174 | * locally. Hence no rw_lock during read. | ||
| 1175 | * | ||
| 1176 | * Take and drop the meta data lock to update inode fields | ||
| 1177 | * like i_size. This allows the checks down below | ||
| 1178 | * generic_file_aio_read() a chance of actually working. | ||
| 1179 | */ | ||
| 1180 | ret = ocfs2_meta_lock(inode, NULL, NULL, 0); | ||
| 1181 | if (ret < 0) { | ||
| 1182 | mlog_errno(ret); | ||
| 1183 | goto bail; | ||
| 1184 | } | ||
| 1185 | ocfs2_meta_unlock(inode, 0); | ||
| 1186 | |||
| 1149 | ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos); | 1187 | ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos); |
| 1150 | if (ret == -EINVAL) | 1188 | if (ret == -EINVAL) |
| 1151 | mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n"); | 1189 | mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n"); |
