diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 288 |
1 files changed, 147 insertions, 141 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 6f482809d1a3..e65493a8ac00 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "meta_io.h" | 21 | #include "meta_io.h" |
22 | #include "quota.h" | 22 | #include "quota.h" |
23 | #include "rgrp.h" | 23 | #include "rgrp.h" |
24 | #include "super.h" | ||
24 | #include "trans.h" | 25 | #include "trans.h" |
25 | #include "dir.h" | 26 | #include "dir.h" |
26 | #include "util.h" | 27 | #include "util.h" |
@@ -50,7 +51,7 @@ struct strip_mine { | |||
50 | * @ip: the inode | 51 | * @ip: the inode |
51 | * @dibh: the dinode buffer | 52 | * @dibh: the dinode buffer |
52 | * @block: the block number that was allocated | 53 | * @block: the block number that was allocated |
53 | * @private: any locked page held by the caller process | 54 | * @page: The (optional) page. This is looked up if @page is NULL |
54 | * | 55 | * |
55 | * Returns: errno | 56 | * Returns: errno |
56 | */ | 57 | */ |
@@ -109,8 +110,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
109 | /** | 110 | /** |
110 | * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big | 111 | * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big |
111 | * @ip: The GFS2 inode to unstuff | 112 | * @ip: The GFS2 inode to unstuff |
112 | * @unstuffer: the routine that handles unstuffing a non-zero length file | 113 | * @page: The (optional) page. This is looked up if the @page is NULL |
113 | * @private: private data for the unstuffer | ||
114 | * | 114 | * |
115 | * This routine unstuffs a dinode and returns it to a "normal" state such | 115 | * This routine unstuffs a dinode and returns it to a "normal" state such |
116 | * that the height can be grown in the traditional way. | 116 | * that the height can be grown in the traditional way. |
@@ -132,7 +132,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
132 | if (error) | 132 | if (error) |
133 | goto out; | 133 | goto out; |
134 | 134 | ||
135 | if (ip->i_disksize) { | 135 | if (i_size_read(&ip->i_inode)) { |
136 | /* Get a free block, fill it with the stuffed data, | 136 | /* Get a free block, fill it with the stuffed data, |
137 | and write it out to disk */ | 137 | and write it out to disk */ |
138 | 138 | ||
@@ -161,7 +161,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
161 | di = (struct gfs2_dinode *)dibh->b_data; | 161 | di = (struct gfs2_dinode *)dibh->b_data; |
162 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 162 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
163 | 163 | ||
164 | if (ip->i_disksize) { | 164 | if (i_size_read(&ip->i_inode)) { |
165 | *(__be64 *)(di + 1) = cpu_to_be64(block); | 165 | *(__be64 *)(di + 1) = cpu_to_be64(block); |
166 | gfs2_add_inode_blocks(&ip->i_inode, 1); | 166 | gfs2_add_inode_blocks(&ip->i_inode, 1); |
167 | di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); | 167 | di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); |
@@ -758,13 +758,13 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
758 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 758 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
759 | struct gfs2_rgrp_list rlist; | 759 | struct gfs2_rgrp_list rlist; |
760 | u64 bn, bstart; | 760 | u64 bn, bstart; |
761 | u32 blen; | 761 | u32 blen, btotal; |
762 | __be64 *p; | 762 | __be64 *p; |
763 | unsigned int rg_blocks = 0; | 763 | unsigned int rg_blocks = 0; |
764 | int metadata; | 764 | int metadata; |
765 | unsigned int revokes = 0; | 765 | unsigned int revokes = 0; |
766 | int x; | 766 | int x; |
767 | int error; | 767 | int error = 0; |
768 | 768 | ||
769 | if (!*top) | 769 | if (!*top) |
770 | sm->sm_first = 0; | 770 | sm->sm_first = 0; |
@@ -780,8 +780,14 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
780 | metadata = (height != ip->i_height - 1); | 780 | metadata = (height != ip->i_height - 1); |
781 | if (metadata) | 781 | if (metadata) |
782 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; | 782 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; |
783 | else if (ip->i_depth) | ||
784 | revokes = sdp->sd_inptrs; | ||
785 | |||
786 | if (ip != GFS2_I(sdp->sd_rindex)) | ||
787 | error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); | ||
788 | else if (!sdp->sd_rgrps) | ||
789 | error = gfs2_ri_update(ip); | ||
783 | 790 | ||
784 | error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); | ||
785 | if (error) | 791 | if (error) |
786 | return error; | 792 | return error; |
787 | 793 | ||
@@ -836,6 +842,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
836 | 842 | ||
837 | bstart = 0; | 843 | bstart = 0; |
838 | blen = 0; | 844 | blen = 0; |
845 | btotal = 0; | ||
839 | 846 | ||
840 | for (p = top; p < bottom; p++) { | 847 | for (p = top; p < bottom; p++) { |
841 | if (!*p) | 848 | if (!*p) |
@@ -848,9 +855,11 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
848 | else { | 855 | else { |
849 | if (bstart) { | 856 | if (bstart) { |
850 | if (metadata) | 857 | if (metadata) |
851 | gfs2_free_meta(ip, bstart, blen); | 858 | __gfs2_free_meta(ip, bstart, blen); |
852 | else | 859 | else |
853 | gfs2_free_data(ip, bstart, blen); | 860 | __gfs2_free_data(ip, bstart, blen); |
861 | |||
862 | btotal += blen; | ||
854 | } | 863 | } |
855 | 864 | ||
856 | bstart = bn; | 865 | bstart = bn; |
@@ -862,11 +871,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
862 | } | 871 | } |
863 | if (bstart) { | 872 | if (bstart) { |
864 | if (metadata) | 873 | if (metadata) |
865 | gfs2_free_meta(ip, bstart, blen); | 874 | __gfs2_free_meta(ip, bstart, blen); |
866 | else | 875 | else |
867 | gfs2_free_data(ip, bstart, blen); | 876 | __gfs2_free_data(ip, bstart, blen); |
877 | |||
878 | btotal += blen; | ||
868 | } | 879 | } |
869 | 880 | ||
881 | gfs2_statfs_change(sdp, 0, +btotal, 0); | ||
882 | gfs2_quota_change(ip, -(s64)btotal, ip->i_inode.i_uid, | ||
883 | ip->i_inode.i_gid); | ||
884 | |||
870 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | 885 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
871 | 886 | ||
872 | gfs2_dinode_out(ip, dibh->b_data); | 887 | gfs2_dinode_out(ip, dibh->b_data); |
@@ -880,88 +895,20 @@ out_rg_gunlock: | |||
880 | out_rlist: | 895 | out_rlist: |
881 | gfs2_rlist_free(&rlist); | 896 | gfs2_rlist_free(&rlist); |
882 | out: | 897 | out: |
883 | gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); | 898 | if (ip != GFS2_I(sdp->sd_rindex)) |
884 | return error; | 899 | gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); |
885 | } | ||
886 | |||
887 | /** | ||
888 | * do_grow - Make a file look bigger than it is | ||
889 | * @ip: the inode | ||
890 | * @size: the size to set the file to | ||
891 | * | ||
892 | * Called with an exclusive lock on @ip. | ||
893 | * | ||
894 | * Returns: errno | ||
895 | */ | ||
896 | |||
897 | static int do_grow(struct gfs2_inode *ip, u64 size) | ||
898 | { | ||
899 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
900 | struct gfs2_alloc *al; | ||
901 | struct buffer_head *dibh; | ||
902 | int error; | ||
903 | |||
904 | al = gfs2_alloc_get(ip); | ||
905 | if (!al) | ||
906 | return -ENOMEM; | ||
907 | |||
908 | error = gfs2_quota_lock_check(ip); | ||
909 | if (error) | ||
910 | goto out; | ||
911 | |||
912 | al->al_requested = sdp->sd_max_height + RES_DATA; | ||
913 | |||
914 | error = gfs2_inplace_reserve(ip); | ||
915 | if (error) | ||
916 | goto out_gunlock_q; | ||
917 | |||
918 | error = gfs2_trans_begin(sdp, | ||
919 | sdp->sd_max_height + al->al_rgd->rd_length + | ||
920 | RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0); | ||
921 | if (error) | ||
922 | goto out_ipres; | ||
923 | |||
924 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
925 | if (error) | ||
926 | goto out_end_trans; | ||
927 | |||
928 | if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { | ||
929 | if (gfs2_is_stuffed(ip)) { | ||
930 | error = gfs2_unstuff_dinode(ip, NULL); | ||
931 | if (error) | ||
932 | goto out_brelse; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | ip->i_disksize = size; | ||
937 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | ||
938 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
939 | gfs2_dinode_out(ip, dibh->b_data); | ||
940 | |||
941 | out_brelse: | ||
942 | brelse(dibh); | ||
943 | out_end_trans: | ||
944 | gfs2_trans_end(sdp); | ||
945 | out_ipres: | ||
946 | gfs2_inplace_release(ip); | ||
947 | out_gunlock_q: | ||
948 | gfs2_quota_unlock(ip); | ||
949 | out: | ||
950 | gfs2_alloc_put(ip); | ||
951 | return error; | 900 | return error; |
952 | } | 901 | } |
953 | 902 | ||
954 | |||
955 | /** | 903 | /** |
956 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate | 904 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate |
957 | * | 905 | * |
958 | * This is partly borrowed from ext3. | 906 | * This is partly borrowed from ext3. |
959 | */ | 907 | */ |
960 | static int gfs2_block_truncate_page(struct address_space *mapping) | 908 | static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) |
961 | { | 909 | { |
962 | struct inode *inode = mapping->host; | 910 | struct inode *inode = mapping->host; |
963 | struct gfs2_inode *ip = GFS2_I(inode); | 911 | struct gfs2_inode *ip = GFS2_I(inode); |
964 | loff_t from = inode->i_size; | ||
965 | unsigned long index = from >> PAGE_CACHE_SHIFT; | 912 | unsigned long index = from >> PAGE_CACHE_SHIFT; |
966 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | 913 | unsigned offset = from & (PAGE_CACHE_SIZE-1); |
967 | unsigned blocksize, iblock, length, pos; | 914 | unsigned blocksize, iblock, length, pos; |
@@ -1023,9 +970,11 @@ unlock: | |||
1023 | return err; | 970 | return err; |
1024 | } | 971 | } |
1025 | 972 | ||
1026 | static int trunc_start(struct gfs2_inode *ip, u64 size) | 973 | static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize) |
1027 | { | 974 | { |
1028 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 975 | struct gfs2_inode *ip = GFS2_I(inode); |
976 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
977 | struct address_space *mapping = inode->i_mapping; | ||
1029 | struct buffer_head *dibh; | 978 | struct buffer_head *dibh; |
1030 | int journaled = gfs2_is_jdata(ip); | 979 | int journaled = gfs2_is_jdata(ip); |
1031 | int error; | 980 | int error; |
@@ -1039,31 +988,26 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) | |||
1039 | if (error) | 988 | if (error) |
1040 | goto out; | 989 | goto out; |
1041 | 990 | ||
991 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
992 | |||
1042 | if (gfs2_is_stuffed(ip)) { | 993 | if (gfs2_is_stuffed(ip)) { |
1043 | u64 dsize = size + sizeof(struct gfs2_dinode); | 994 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize); |
1044 | ip->i_disksize = size; | ||
1045 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | ||
1046 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
1047 | gfs2_dinode_out(ip, dibh->b_data); | ||
1048 | if (dsize > dibh->b_size) | ||
1049 | dsize = dibh->b_size; | ||
1050 | gfs2_buffer_clear_tail(dibh, dsize); | ||
1051 | error = 1; | ||
1052 | } else { | 995 | } else { |
1053 | if (size & (u64)(sdp->sd_sb.sb_bsize - 1)) | 996 | if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) { |
1054 | error = gfs2_block_truncate_page(ip->i_inode.i_mapping); | 997 | error = gfs2_block_truncate_page(mapping, newsize); |
1055 | 998 | if (error) | |
1056 | if (!error) { | 999 | goto out_brelse; |
1057 | ip->i_disksize = size; | ||
1058 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | ||
1059 | ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; | ||
1060 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
1061 | gfs2_dinode_out(ip, dibh->b_data); | ||
1062 | } | 1000 | } |
1001 | ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; | ||
1063 | } | 1002 | } |
1064 | 1003 | ||
1065 | brelse(dibh); | 1004 | i_size_write(inode, newsize); |
1005 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | ||
1006 | gfs2_dinode_out(ip, dibh->b_data); | ||
1066 | 1007 | ||
1008 | truncate_pagecache(inode, oldsize, newsize); | ||
1009 | out_brelse: | ||
1010 | brelse(dibh); | ||
1067 | out: | 1011 | out: |
1068 | gfs2_trans_end(sdp); | 1012 | gfs2_trans_end(sdp); |
1069 | return error; | 1013 | return error; |
@@ -1123,7 +1067,7 @@ static int trunc_end(struct gfs2_inode *ip) | |||
1123 | if (error) | 1067 | if (error) |
1124 | goto out; | 1068 | goto out; |
1125 | 1069 | ||
1126 | if (!ip->i_disksize) { | 1070 | if (!i_size_read(&ip->i_inode)) { |
1127 | ip->i_height = 0; | 1071 | ip->i_height = 0; |
1128 | ip->i_goal = ip->i_no_addr; | 1072 | ip->i_goal = ip->i_no_addr; |
1129 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 1073 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
@@ -1143,92 +1087,154 @@ out: | |||
1143 | 1087 | ||
1144 | /** | 1088 | /** |
1145 | * do_shrink - make a file smaller | 1089 | * do_shrink - make a file smaller |
1146 | * @ip: the inode | 1090 | * @inode: the inode |
1147 | * @size: the size to make the file | 1091 | * @oldsize: the current inode size |
1148 | * @truncator: function to truncate the last partial block | 1092 | * @newsize: the size to make the file |
1149 | * | 1093 | * |
1150 | * Called with an exclusive lock on @ip. | 1094 | * Called with an exclusive lock on @inode. The @size must |
1095 | * be equal to or smaller than the current inode size. | ||
1151 | * | 1096 | * |
1152 | * Returns: errno | 1097 | * Returns: errno |
1153 | */ | 1098 | */ |
1154 | 1099 | ||
1155 | static int do_shrink(struct gfs2_inode *ip, u64 size) | 1100 | static int do_shrink(struct inode *inode, u64 oldsize, u64 newsize) |
1156 | { | 1101 | { |
1102 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1157 | int error; | 1103 | int error; |
1158 | 1104 | ||
1159 | error = trunc_start(ip, size); | 1105 | error = trunc_start(inode, oldsize, newsize); |
1160 | if (error < 0) | 1106 | if (error < 0) |
1161 | return error; | 1107 | return error; |
1162 | if (error > 0) | 1108 | if (gfs2_is_stuffed(ip)) |
1163 | return 0; | 1109 | return 0; |
1164 | 1110 | ||
1165 | error = trunc_dealloc(ip, size); | 1111 | error = trunc_dealloc(ip, newsize); |
1166 | if (!error) | 1112 | if (error == 0) |
1167 | error = trunc_end(ip); | 1113 | error = trunc_end(ip); |
1168 | 1114 | ||
1169 | return error; | 1115 | return error; |
1170 | } | 1116 | } |
1171 | 1117 | ||
1172 | static int do_touch(struct gfs2_inode *ip, u64 size) | 1118 | void gfs2_trim_blocks(struct inode *inode) |
1173 | { | 1119 | { |
1174 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1120 | u64 size = inode->i_size; |
1121 | int ret; | ||
1122 | |||
1123 | ret = do_shrink(inode, size, size); | ||
1124 | WARN_ON(ret != 0); | ||
1125 | } | ||
1126 | |||
1127 | /** | ||
1128 | * do_grow - Touch and update inode size | ||
1129 | * @inode: The inode | ||
1130 | * @size: The new size | ||
1131 | * | ||
1132 | * This function updates the timestamps on the inode and | ||
1133 | * may also increase the size of the inode. This function | ||
1134 | * must not be called with @size any smaller than the current | ||
1135 | * inode size. | ||
1136 | * | ||
1137 | * Although it is not strictly required to unstuff files here, | ||
1138 | * earlier versions of GFS2 have a bug in the stuffed file reading | ||
1139 | * code which will result in a buffer overrun if the size is larger | ||
1140 | * than the max stuffed file size. In order to prevent this from | ||
1141 | * occurring, such files are unstuffed, but in other cases we can | ||
1142 | * just update the inode size directly. | ||
1143 | * | ||
1144 | * Returns: 0 on success, or -ve on error | ||
1145 | */ | ||
1146 | |||
1147 | static int do_grow(struct inode *inode, u64 size) | ||
1148 | { | ||
1149 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1150 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
1175 | struct buffer_head *dibh; | 1151 | struct buffer_head *dibh; |
1152 | struct gfs2_alloc *al = NULL; | ||
1176 | int error; | 1153 | int error; |
1177 | 1154 | ||
1178 | error = gfs2_trans_begin(sdp, RES_DINODE, 0); | 1155 | if (gfs2_is_stuffed(ip) && |
1156 | (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) { | ||
1157 | al = gfs2_alloc_get(ip); | ||
1158 | if (al == NULL) | ||
1159 | return -ENOMEM; | ||
1160 | |||
1161 | error = gfs2_quota_lock_check(ip); | ||
1162 | if (error) | ||
1163 | goto do_grow_alloc_put; | ||
1164 | |||
1165 | al->al_requested = 1; | ||
1166 | error = gfs2_inplace_reserve(ip); | ||
1167 | if (error) | ||
1168 | goto do_grow_qunlock; | ||
1169 | } | ||
1170 | |||
1171 | error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT, 0); | ||
1179 | if (error) | 1172 | if (error) |
1180 | return error; | 1173 | goto do_grow_release; |
1181 | 1174 | ||
1182 | down_write(&ip->i_rw_mutex); | 1175 | if (al) { |
1176 | error = gfs2_unstuff_dinode(ip, NULL); | ||
1177 | if (error) | ||
1178 | goto do_end_trans; | ||
1179 | } | ||
1183 | 1180 | ||
1184 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1181 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1185 | if (error) | 1182 | if (error) |
1186 | goto do_touch_out; | 1183 | goto do_end_trans; |
1187 | 1184 | ||
1185 | i_size_write(inode, size); | ||
1188 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | 1186 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
1189 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1187 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
1190 | gfs2_dinode_out(ip, dibh->b_data); | 1188 | gfs2_dinode_out(ip, dibh->b_data); |
1191 | brelse(dibh); | 1189 | brelse(dibh); |
1192 | 1190 | ||
1193 | do_touch_out: | 1191 | do_end_trans: |
1194 | up_write(&ip->i_rw_mutex); | ||
1195 | gfs2_trans_end(sdp); | 1192 | gfs2_trans_end(sdp); |
1193 | do_grow_release: | ||
1194 | if (al) { | ||
1195 | gfs2_inplace_release(ip); | ||
1196 | do_grow_qunlock: | ||
1197 | gfs2_quota_unlock(ip); | ||
1198 | do_grow_alloc_put: | ||
1199 | gfs2_alloc_put(ip); | ||
1200 | } | ||
1196 | return error; | 1201 | return error; |
1197 | } | 1202 | } |
1198 | 1203 | ||
1199 | /** | 1204 | /** |
1200 | * gfs2_truncatei - make a file a given size | 1205 | * gfs2_setattr_size - make a file a given size |
1201 | * @ip: the inode | 1206 | * @inode: the inode |
1202 | * @size: the size to make the file | 1207 | * @newsize: the size to make the file |
1203 | * @truncator: function to truncate the last partial block | ||
1204 | * | 1208 | * |
1205 | * The file size can grow, shrink, or stay the same size. | 1209 | * The file size can grow, shrink, or stay the same size. This |
1210 | * is called holding i_mutex and an exclusive glock on the inode | ||
1211 | * in question. | ||
1206 | * | 1212 | * |
1207 | * Returns: errno | 1213 | * Returns: errno |
1208 | */ | 1214 | */ |
1209 | 1215 | ||
1210 | int gfs2_truncatei(struct gfs2_inode *ip, u64 size) | 1216 | int gfs2_setattr_size(struct inode *inode, u64 newsize) |
1211 | { | 1217 | { |
1212 | int error; | 1218 | int ret; |
1219 | u64 oldsize; | ||
1213 | 1220 | ||
1214 | if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode))) | 1221 | BUG_ON(!S_ISREG(inode->i_mode)); |
1215 | return -EINVAL; | ||
1216 | 1222 | ||
1217 | if (size > ip->i_disksize) | 1223 | ret = inode_newsize_ok(inode, newsize); |
1218 | error = do_grow(ip, size); | 1224 | if (ret) |
1219 | else if (size < ip->i_disksize) | 1225 | return ret; |
1220 | error = do_shrink(ip, size); | ||
1221 | else | ||
1222 | /* update time stamps */ | ||
1223 | error = do_touch(ip, size); | ||
1224 | 1226 | ||
1225 | return error; | 1227 | oldsize = inode->i_size; |
1228 | if (newsize >= oldsize) | ||
1229 | return do_grow(inode, newsize); | ||
1230 | |||
1231 | return do_shrink(inode, oldsize, newsize); | ||
1226 | } | 1232 | } |
1227 | 1233 | ||
1228 | int gfs2_truncatei_resume(struct gfs2_inode *ip) | 1234 | int gfs2_truncatei_resume(struct gfs2_inode *ip) |
1229 | { | 1235 | { |
1230 | int error; | 1236 | int error; |
1231 | error = trunc_dealloc(ip, ip->i_disksize); | 1237 | error = trunc_dealloc(ip, i_size_read(&ip->i_inode)); |
1232 | if (!error) | 1238 | if (!error) |
1233 | error = trunc_end(ip); | 1239 | error = trunc_end(ip); |
1234 | return error; | 1240 | return error; |
@@ -1269,7 +1275,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, | |||
1269 | 1275 | ||
1270 | shift = sdp->sd_sb.sb_bsize_shift; | 1276 | shift = sdp->sd_sb.sb_bsize_shift; |
1271 | BUG_ON(gfs2_is_dir(ip)); | 1277 | BUG_ON(gfs2_is_dir(ip)); |
1272 | end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift; | 1278 | end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift; |
1273 | lblock = offset >> shift; | 1279 | lblock = offset >> shift; |
1274 | lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; | 1280 | lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; |
1275 | if (lblock_stop > end_of_file) | 1281 | if (lblock_stop > end_of_file) |