diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 255 |
1 files changed, 122 insertions, 133 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 6f482809d1a3..5476c066d4ee 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -50,7 +50,7 @@ struct strip_mine { | |||
50 | * @ip: the inode | 50 | * @ip: the inode |
51 | * @dibh: the dinode buffer | 51 | * @dibh: the dinode buffer |
52 | * @block: the block number that was allocated | 52 | * @block: the block number that was allocated |
53 | * @private: any locked page held by the caller process | 53 | * @page: The (optional) page. This is looked up if @page is NULL |
54 | * | 54 | * |
55 | * Returns: errno | 55 | * Returns: errno |
56 | */ | 56 | */ |
@@ -109,8 +109,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
109 | /** | 109 | /** |
110 | * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big | 110 | * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big |
111 | * @ip: The GFS2 inode to unstuff | 111 | * @ip: The GFS2 inode to unstuff |
112 | * @unstuffer: the routine that handles unstuffing a non-zero length file | 112 | * @page: The (optional) page. This is looked up if the @page is NULL |
113 | * @private: private data for the unstuffer | ||
114 | * | 113 | * |
115 | * This routine unstuffs a dinode and returns it to a "normal" state such | 114 | * This routine unstuffs a dinode and returns it to a "normal" state such |
116 | * that the height can be grown in the traditional way. | 115 | * that the height can be grown in the traditional way. |
@@ -132,7 +131,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
132 | if (error) | 131 | if (error) |
133 | goto out; | 132 | goto out; |
134 | 133 | ||
135 | if (ip->i_disksize) { | 134 | if (i_size_read(&ip->i_inode)) { |
136 | /* Get a free block, fill it with the stuffed data, | 135 | /* Get a free block, fill it with the stuffed data, |
137 | and write it out to disk */ | 136 | and write it out to disk */ |
138 | 137 | ||
@@ -161,7 +160,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
161 | di = (struct gfs2_dinode *)dibh->b_data; | 160 | di = (struct gfs2_dinode *)dibh->b_data; |
162 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 161 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
163 | 162 | ||
164 | if (ip->i_disksize) { | 163 | if (i_size_read(&ip->i_inode)) { |
165 | *(__be64 *)(di + 1) = cpu_to_be64(block); | 164 | *(__be64 *)(di + 1) = cpu_to_be64(block); |
166 | gfs2_add_inode_blocks(&ip->i_inode, 1); | 165 | gfs2_add_inode_blocks(&ip->i_inode, 1); |
167 | di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); | 166 | di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); |
@@ -885,83 +884,14 @@ out: | |||
885 | } | 884 | } |
886 | 885 | ||
887 | /** | 886 | /** |
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; | ||
952 | } | ||
953 | |||
954 | |||
955 | /** | ||
956 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate | 887 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate |
957 | * | 888 | * |
958 | * This is partly borrowed from ext3. | 889 | * This is partly borrowed from ext3. |
959 | */ | 890 | */ |
960 | static int gfs2_block_truncate_page(struct address_space *mapping) | 891 | static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) |
961 | { | 892 | { |
962 | struct inode *inode = mapping->host; | 893 | struct inode *inode = mapping->host; |
963 | struct gfs2_inode *ip = GFS2_I(inode); | 894 | struct gfs2_inode *ip = GFS2_I(inode); |
964 | loff_t from = inode->i_size; | ||
965 | unsigned long index = from >> PAGE_CACHE_SHIFT; | 895 | unsigned long index = from >> PAGE_CACHE_SHIFT; |
966 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | 896 | unsigned offset = from & (PAGE_CACHE_SIZE-1); |
967 | unsigned blocksize, iblock, length, pos; | 897 | unsigned blocksize, iblock, length, pos; |
@@ -1023,9 +953,11 @@ unlock: | |||
1023 | return err; | 953 | return err; |
1024 | } | 954 | } |
1025 | 955 | ||
1026 | static int trunc_start(struct gfs2_inode *ip, u64 size) | 956 | static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize) |
1027 | { | 957 | { |
1028 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 958 | struct gfs2_inode *ip = GFS2_I(inode); |
959 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
960 | struct address_space *mapping = inode->i_mapping; | ||
1029 | struct buffer_head *dibh; | 961 | struct buffer_head *dibh; |
1030 | int journaled = gfs2_is_jdata(ip); | 962 | int journaled = gfs2_is_jdata(ip); |
1031 | int error; | 963 | int error; |
@@ -1039,31 +971,26 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) | |||
1039 | if (error) | 971 | if (error) |
1040 | goto out; | 972 | goto out; |
1041 | 973 | ||
974 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
975 | |||
1042 | if (gfs2_is_stuffed(ip)) { | 976 | if (gfs2_is_stuffed(ip)) { |
1043 | u64 dsize = size + sizeof(struct gfs2_dinode); | 977 | 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 { | 978 | } else { |
1053 | if (size & (u64)(sdp->sd_sb.sb_bsize - 1)) | 979 | if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) { |
1054 | error = gfs2_block_truncate_page(ip->i_inode.i_mapping); | 980 | error = gfs2_block_truncate_page(mapping, newsize); |
1055 | 981 | if (error) | |
1056 | if (!error) { | 982 | 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 | } | 983 | } |
984 | ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; | ||
1063 | } | 985 | } |
1064 | 986 | ||
1065 | brelse(dibh); | 987 | i_size_write(inode, newsize); |
988 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | ||
989 | gfs2_dinode_out(ip, dibh->b_data); | ||
1066 | 990 | ||
991 | truncate_pagecache(inode, oldsize, newsize); | ||
992 | out_brelse: | ||
993 | brelse(dibh); | ||
1067 | out: | 994 | out: |
1068 | gfs2_trans_end(sdp); | 995 | gfs2_trans_end(sdp); |
1069 | return error; | 996 | return error; |
@@ -1123,7 +1050,7 @@ static int trunc_end(struct gfs2_inode *ip) | |||
1123 | if (error) | 1050 | if (error) |
1124 | goto out; | 1051 | goto out; |
1125 | 1052 | ||
1126 | if (!ip->i_disksize) { | 1053 | if (!i_size_read(&ip->i_inode)) { |
1127 | ip->i_height = 0; | 1054 | ip->i_height = 0; |
1128 | ip->i_goal = ip->i_no_addr; | 1055 | ip->i_goal = ip->i_no_addr; |
1129 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 1056 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
@@ -1143,92 +1070,154 @@ out: | |||
1143 | 1070 | ||
1144 | /** | 1071 | /** |
1145 | * do_shrink - make a file smaller | 1072 | * do_shrink - make a file smaller |
1146 | * @ip: the inode | 1073 | * @inode: the inode |
1147 | * @size: the size to make the file | 1074 | * @oldsize: the current inode size |
1148 | * @truncator: function to truncate the last partial block | 1075 | * @newsize: the size to make the file |
1149 | * | 1076 | * |
1150 | * Called with an exclusive lock on @ip. | 1077 | * Called with an exclusive lock on @inode. The @size must |
1078 | * be equal to or smaller than the current inode size. | ||
1151 | * | 1079 | * |
1152 | * Returns: errno | 1080 | * Returns: errno |
1153 | */ | 1081 | */ |
1154 | 1082 | ||
1155 | static int do_shrink(struct gfs2_inode *ip, u64 size) | 1083 | static int do_shrink(struct inode *inode, u64 oldsize, u64 newsize) |
1156 | { | 1084 | { |
1085 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1157 | int error; | 1086 | int error; |
1158 | 1087 | ||
1159 | error = trunc_start(ip, size); | 1088 | error = trunc_start(inode, oldsize, newsize); |
1160 | if (error < 0) | 1089 | if (error < 0) |
1161 | return error; | 1090 | return error; |
1162 | if (error > 0) | 1091 | if (gfs2_is_stuffed(ip)) |
1163 | return 0; | 1092 | return 0; |
1164 | 1093 | ||
1165 | error = trunc_dealloc(ip, size); | 1094 | error = trunc_dealloc(ip, newsize); |
1166 | if (!error) | 1095 | if (error == 0) |
1167 | error = trunc_end(ip); | 1096 | error = trunc_end(ip); |
1168 | 1097 | ||
1169 | return error; | 1098 | return error; |
1170 | } | 1099 | } |
1171 | 1100 | ||
1172 | static int do_touch(struct gfs2_inode *ip, u64 size) | 1101 | void gfs2_trim_blocks(struct inode *inode) |
1173 | { | 1102 | { |
1174 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1103 | u64 size = inode->i_size; |
1104 | int ret; | ||
1105 | |||
1106 | ret = do_shrink(inode, size, size); | ||
1107 | WARN_ON(ret != 0); | ||
1108 | } | ||
1109 | |||
1110 | /** | ||
1111 | * do_grow - Touch and update inode size | ||
1112 | * @inode: The inode | ||
1113 | * @size: The new size | ||
1114 | * | ||
1115 | * This function updates the timestamps on the inode and | ||
1116 | * may also increase the size of the inode. This function | ||
1117 | * must not be called with @size any smaller than the current | ||
1118 | * inode size. | ||
1119 | * | ||
1120 | * Although it is not strictly required to unstuff files here, | ||
1121 | * earlier versions of GFS2 have a bug in the stuffed file reading | ||
1122 | * code which will result in a buffer overrun if the size is larger | ||
1123 | * than the max stuffed file size. In order to prevent this from | ||
1124 | * occuring, such files are unstuffed, but in other cases we can | ||
1125 | * just update the inode size directly. | ||
1126 | * | ||
1127 | * Returns: 0 on success, or -ve on error | ||
1128 | */ | ||
1129 | |||
1130 | static int do_grow(struct inode *inode, u64 size) | ||
1131 | { | ||
1132 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1133 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
1175 | struct buffer_head *dibh; | 1134 | struct buffer_head *dibh; |
1135 | struct gfs2_alloc *al = NULL; | ||
1176 | int error; | 1136 | int error; |
1177 | 1137 | ||
1178 | error = gfs2_trans_begin(sdp, RES_DINODE, 0); | 1138 | if (gfs2_is_stuffed(ip) && |
1139 | (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) { | ||
1140 | al = gfs2_alloc_get(ip); | ||
1141 | if (al == NULL) | ||
1142 | return -ENOMEM; | ||
1143 | |||
1144 | error = gfs2_quota_lock_check(ip); | ||
1145 | if (error) | ||
1146 | goto do_grow_alloc_put; | ||
1147 | |||
1148 | al->al_requested = 1; | ||
1149 | error = gfs2_inplace_reserve(ip); | ||
1150 | if (error) | ||
1151 | goto do_grow_qunlock; | ||
1152 | } | ||
1153 | |||
1154 | error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT, 0); | ||
1179 | if (error) | 1155 | if (error) |
1180 | return error; | 1156 | goto do_grow_release; |
1181 | 1157 | ||
1182 | down_write(&ip->i_rw_mutex); | 1158 | if (al) { |
1159 | error = gfs2_unstuff_dinode(ip, NULL); | ||
1160 | if (error) | ||
1161 | goto do_end_trans; | ||
1162 | } | ||
1183 | 1163 | ||
1184 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1164 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1185 | if (error) | 1165 | if (error) |
1186 | goto do_touch_out; | 1166 | goto do_end_trans; |
1187 | 1167 | ||
1168 | i_size_write(inode, size); | ||
1188 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | 1169 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
1189 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1170 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
1190 | gfs2_dinode_out(ip, dibh->b_data); | 1171 | gfs2_dinode_out(ip, dibh->b_data); |
1191 | brelse(dibh); | 1172 | brelse(dibh); |
1192 | 1173 | ||
1193 | do_touch_out: | 1174 | do_end_trans: |
1194 | up_write(&ip->i_rw_mutex); | ||
1195 | gfs2_trans_end(sdp); | 1175 | gfs2_trans_end(sdp); |
1176 | do_grow_release: | ||
1177 | if (al) { | ||
1178 | gfs2_inplace_release(ip); | ||
1179 | do_grow_qunlock: | ||
1180 | gfs2_quota_unlock(ip); | ||
1181 | do_grow_alloc_put: | ||
1182 | gfs2_alloc_put(ip); | ||
1183 | } | ||
1196 | return error; | 1184 | return error; |
1197 | } | 1185 | } |
1198 | 1186 | ||
1199 | /** | 1187 | /** |
1200 | * gfs2_truncatei - make a file a given size | 1188 | * gfs2_setattr_size - make a file a given size |
1201 | * @ip: the inode | 1189 | * @inode: the inode |
1202 | * @size: the size to make the file | 1190 | * @newsize: the size to make the file |
1203 | * @truncator: function to truncate the last partial block | ||
1204 | * | 1191 | * |
1205 | * The file size can grow, shrink, or stay the same size. | 1192 | * The file size can grow, shrink, or stay the same size. This |
1193 | * is called holding i_mutex and an exclusive glock on the inode | ||
1194 | * in question. | ||
1206 | * | 1195 | * |
1207 | * Returns: errno | 1196 | * Returns: errno |
1208 | */ | 1197 | */ |
1209 | 1198 | ||
1210 | int gfs2_truncatei(struct gfs2_inode *ip, u64 size) | 1199 | int gfs2_setattr_size(struct inode *inode, u64 newsize) |
1211 | { | 1200 | { |
1212 | int error; | 1201 | int ret; |
1202 | u64 oldsize; | ||
1213 | 1203 | ||
1214 | if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode))) | 1204 | BUG_ON(!S_ISREG(inode->i_mode)); |
1215 | return -EINVAL; | ||
1216 | 1205 | ||
1217 | if (size > ip->i_disksize) | 1206 | ret = inode_newsize_ok(inode, newsize); |
1218 | error = do_grow(ip, size); | 1207 | if (ret) |
1219 | else if (size < ip->i_disksize) | 1208 | return ret; |
1220 | error = do_shrink(ip, size); | ||
1221 | else | ||
1222 | /* update time stamps */ | ||
1223 | error = do_touch(ip, size); | ||
1224 | 1209 | ||
1225 | return error; | 1210 | oldsize = inode->i_size; |
1211 | if (newsize >= oldsize) | ||
1212 | return do_grow(inode, newsize); | ||
1213 | |||
1214 | return do_shrink(inode, oldsize, newsize); | ||
1226 | } | 1215 | } |
1227 | 1216 | ||
1228 | int gfs2_truncatei_resume(struct gfs2_inode *ip) | 1217 | int gfs2_truncatei_resume(struct gfs2_inode *ip) |
1229 | { | 1218 | { |
1230 | int error; | 1219 | int error; |
1231 | error = trunc_dealloc(ip, ip->i_disksize); | 1220 | error = trunc_dealloc(ip, i_size_read(&ip->i_inode)); |
1232 | if (!error) | 1221 | if (!error) |
1233 | error = trunc_end(ip); | 1222 | error = trunc_end(ip); |
1234 | return error; | 1223 | return error; |
@@ -1269,7 +1258,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, | |||
1269 | 1258 | ||
1270 | shift = sdp->sd_sb.sb_bsize_shift; | 1259 | shift = sdp->sd_sb.sb_bsize_shift; |
1271 | BUG_ON(gfs2_is_dir(ip)); | 1260 | BUG_ON(gfs2_is_dir(ip)); |
1272 | end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift; | 1261 | end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift; |
1273 | lblock = offset >> shift; | 1262 | lblock = offset >> shift; |
1274 | lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; | 1263 | lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; |
1275 | if (lblock_stop > end_of_file) | 1264 | if (lblock_stop > end_of_file) |