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) |
