Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

GFS2: New truncate sequence

This updates GFS2's truncate code to use the new truncate
sequence correctly. This is a stepping stone to being
able to remove ip->i_disksize in favour of using i_size
everywhere now that the two sizes are always identical.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Cc: Nick Piggin <npiggin@suse.de>
Cc: Christoph Hellwig <hch@lst.de>

+137 -170
+4 -6
fs/gfs2/aops.c
··· 696 696 697 697 page_cache_release(page); 698 698 699 - /* 700 - * XXX(truncate): the call below should probably be replaced with 701 - * a call to the gfs2-specific truncate blocks helper to actually 702 - * release disk blocks.. 703 - */ 699 + gfs2_trans_end(sdp); 704 700 if (pos + len > ip->i_inode.i_size) 705 - truncate_setsize(&ip->i_inode, ip->i_inode.i_size); 701 + gfs2_trim_blocks(&ip->i_inode); 702 + goto out_trans_fail; 703 + 706 704 out_endtrans: 707 705 gfs2_trans_end(sdp); 708 706 out_trans_fail:
+121 -130
fs/gfs2/bmap.c
··· 50 50 * @ip: the inode 51 51 * @dibh: the dinode buffer 52 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 55 * Returns: errno 56 56 */ ··· 109 109 /** 110 110 * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big 111 111 * @ip: The GFS2 inode to unstuff 112 - * @unstuffer: the routine that handles unstuffing a non-zero length file 113 - * @private: private data for the unstuffer 112 + * @page: The (optional) page. This is looked up if the @page is NULL 114 113 * 115 114 * This routine unstuffs a dinode and returns it to a "normal" state such 116 115 * that the height can be grown in the traditional way. ··· 884 885 } 885 886 886 887 /** 887 - * do_grow - Make a file look bigger than it is 888 - * @ip: the inode 889 - * @size: the size to set the file to 890 - * 891 - * Called with an exclusive lock on @ip. 892 - * 893 - * Returns: errno 894 - */ 895 - 896 - static int do_grow(struct gfs2_inode *ip, u64 size) 897 - { 898 - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 899 - struct gfs2_alloc *al; 900 - struct buffer_head *dibh; 901 - int error; 902 - 903 - al = gfs2_alloc_get(ip); 904 - if (!al) 905 - return -ENOMEM; 906 - 907 - error = gfs2_quota_lock_check(ip); 908 - if (error) 909 - goto out; 910 - 911 - al->al_requested = sdp->sd_max_height + RES_DATA; 912 - 913 - error = gfs2_inplace_reserve(ip); 914 - if (error) 915 - goto out_gunlock_q; 916 - 917 - error = gfs2_trans_begin(sdp, 918 - sdp->sd_max_height + al->al_rgd->rd_length + 919 - RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0); 920 - if (error) 921 - goto out_ipres; 922 - 923 - error = gfs2_meta_inode_buffer(ip, &dibh); 924 - if (error) 925 - goto out_end_trans; 926 - 927 - if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { 928 - if (gfs2_is_stuffed(ip)) { 929 - error = gfs2_unstuff_dinode(ip, NULL); 930 - if (error) 931 - goto out_brelse; 932 - } 933 - } 934 - 935 - ip->i_disksize = size; 936 - ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 937 - gfs2_trans_add_bh(ip->i_gl, dibh, 1); 938 - gfs2_dinode_out(ip, dibh->b_data); 939 - 940 - out_brelse: 941 - brelse(dibh); 942 - out_end_trans: 943 - gfs2_trans_end(sdp); 944 - out_ipres: 945 - gfs2_inplace_release(ip); 946 - out_gunlock_q: 947 - gfs2_quota_unlock(ip); 948 - out: 949 - gfs2_alloc_put(ip); 950 - return error; 951 - } 952 - 953 - 954 - /** 955 888 * gfs2_block_truncate_page - Deal with zeroing out data for truncate 956 889 * 957 890 * This is partly borrowed from ext3. 958 891 */ 959 - static int gfs2_block_truncate_page(struct address_space *mapping) 892 + static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) 960 893 { 961 894 struct inode *inode = mapping->host; 962 895 struct gfs2_inode *ip = GFS2_I(inode); 963 - loff_t from = inode->i_size; 964 896 unsigned long index = from >> PAGE_CACHE_SHIFT; 965 897 unsigned offset = from & (PAGE_CACHE_SIZE-1); 966 898 unsigned blocksize, iblock, length, pos; ··· 953 1023 return err; 954 1024 } 955 1025 956 - static int trunc_start(struct gfs2_inode *ip, u64 size) 1026 + static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize) 957 1027 { 958 - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 1028 + struct gfs2_inode *ip = GFS2_I(inode); 1029 + struct gfs2_sbd *sdp = GFS2_SB(inode); 1030 + struct address_space *mapping = inode->i_mapping; 959 1031 struct buffer_head *dibh; 960 1032 int journaled = gfs2_is_jdata(ip); 961 1033 int error; ··· 971 1039 if (error) 972 1040 goto out; 973 1041 974 - if (gfs2_is_stuffed(ip)) { 975 - u64 dsize = size + sizeof(struct gfs2_dinode); 976 - ip->i_disksize = size; 977 - ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 978 - gfs2_trans_add_bh(ip->i_gl, dibh, 1); 979 - gfs2_dinode_out(ip, dibh->b_data); 980 - if (dsize > dibh->b_size) 981 - dsize = dibh->b_size; 982 - gfs2_buffer_clear_tail(dibh, dsize); 983 - error = 1; 984 - } else { 985 - if (size & (u64)(sdp->sd_sb.sb_bsize - 1)) 986 - error = gfs2_block_truncate_page(ip->i_inode.i_mapping); 1042 + gfs2_trans_add_bh(ip->i_gl, dibh, 1); 987 1043 988 - if (!error) { 989 - ip->i_disksize = size; 990 - ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 991 - ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; 992 - gfs2_trans_add_bh(ip->i_gl, dibh, 1); 993 - gfs2_dinode_out(ip, dibh->b_data); 1044 + if (gfs2_is_stuffed(ip)) { 1045 + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize); 1046 + } else { 1047 + if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) { 1048 + error = gfs2_block_truncate_page(mapping, newsize); 1049 + if (error) 1050 + goto out_brelse; 994 1051 } 1052 + ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; 995 1053 } 996 1054 997 - brelse(dibh); 1055 + i_size_write(inode, newsize); 1056 + ip->i_disksize = newsize; 1057 + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 1058 + gfs2_dinode_out(ip, dibh->b_data); 998 1059 1060 + truncate_pagecache(inode, oldsize, newsize); 1061 + out_brelse: 1062 + brelse(dibh); 999 1063 out: 1000 1064 gfs2_trans_end(sdp); 1001 1065 return error; ··· 1071 1143 1072 1144 /** 1073 1145 * do_shrink - make a file smaller 1074 - * @ip: the inode 1075 - * @size: the size to make the file 1076 - * @truncator: function to truncate the last partial block 1146 + * @inode: the inode 1147 + * @oldsize: the current inode size 1148 + * @newsize: the size to make the file 1077 1149 * 1078 - * Called with an exclusive lock on @ip. 1150 + * Called with an exclusive lock on @inode. The @size must 1151 + * be equal to or smaller than the current inode size. 1079 1152 * 1080 1153 * Returns: errno 1081 1154 */ 1082 1155 1083 - static int do_shrink(struct gfs2_inode *ip, u64 size) 1156 + static int do_shrink(struct inode *inode, u64 oldsize, u64 newsize) 1084 1157 { 1158 + struct gfs2_inode *ip = GFS2_I(inode); 1085 1159 int error; 1086 1160 1087 - error = trunc_start(ip, size); 1161 + error = trunc_start(inode, oldsize, newsize); 1088 1162 if (error < 0) 1089 1163 return error; 1090 - if (error > 0) 1164 + if (gfs2_is_stuffed(ip)) 1091 1165 return 0; 1092 1166 1093 - error = trunc_dealloc(ip, size); 1094 - if (!error) 1167 + error = trunc_dealloc(ip, newsize); 1168 + if (error == 0) 1095 1169 error = trunc_end(ip); 1096 1170 1097 1171 return error; 1098 1172 } 1099 1173 1100 - static int do_touch(struct gfs2_inode *ip, u64 size) 1174 + void gfs2_trim_blocks(struct inode *inode) 1101 1175 { 1102 - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 1176 + u64 size = inode->i_size; 1177 + int ret; 1178 + 1179 + ret = do_shrink(inode, size, size); 1180 + WARN_ON(ret != 0); 1181 + } 1182 + 1183 + /** 1184 + * do_grow - Touch and update inode size 1185 + * @inode: The inode 1186 + * @size: The new size 1187 + * 1188 + * This function updates the timestamps on the inode and 1189 + * may also increase the size of the inode. This function 1190 + * must not be called with @size any smaller than the current 1191 + * inode size. 1192 + * 1193 + * Although it is not strictly required to unstuff files here, 1194 + * earlier versions of GFS2 have a bug in the stuffed file reading 1195 + * code which will result in a buffer overrun if the size is larger 1196 + * than the max stuffed file size. In order to prevent this from 1197 + * occuring, such files are unstuffed, but in other cases we can 1198 + * just update the inode size directly. 1199 + * 1200 + * Returns: 0 on success, or -ve on error 1201 + */ 1202 + 1203 + static int do_grow(struct inode *inode, u64 size) 1204 + { 1205 + struct gfs2_inode *ip = GFS2_I(inode); 1206 + struct gfs2_sbd *sdp = GFS2_SB(inode); 1103 1207 struct buffer_head *dibh; 1208 + struct gfs2_alloc *al = NULL; 1104 1209 int error; 1105 1210 1106 - error = gfs2_trans_begin(sdp, RES_DINODE, 0); 1107 - if (error) 1108 - return error; 1211 + if (gfs2_is_stuffed(ip) && 1212 + (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) { 1213 + al = gfs2_alloc_get(ip); 1214 + if (al == NULL) 1215 + return -ENOMEM; 1109 1216 1110 - down_write(&ip->i_rw_mutex); 1217 + error = gfs2_quota_lock_check(ip); 1218 + if (error) 1219 + goto do_grow_alloc_put; 1220 + 1221 + al->al_requested = 1; 1222 + error = gfs2_inplace_reserve(ip); 1223 + if (error) 1224 + goto do_grow_qunlock; 1225 + } 1226 + 1227 + error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); 1228 + if (error) 1229 + goto do_grow_release; 1230 + 1231 + if (al) { 1232 + error = gfs2_unstuff_dinode(ip, NULL); 1233 + if (error) 1234 + goto do_end_trans; 1235 + } 1111 1236 1112 1237 error = gfs2_meta_inode_buffer(ip, &dibh); 1113 1238 if (error) 1114 - goto do_touch_out; 1239 + goto do_end_trans; 1115 1240 1241 + i_size_write(inode, size); 1242 + ip->i_disksize = size; 1116 1243 ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 1117 1244 gfs2_trans_add_bh(ip->i_gl, dibh, 1); 1118 1245 gfs2_dinode_out(ip, dibh->b_data); 1119 1246 brelse(dibh); 1120 1247 1121 - do_touch_out: 1122 - up_write(&ip->i_rw_mutex); 1248 + do_end_trans: 1123 1249 gfs2_trans_end(sdp); 1250 + do_grow_release: 1251 + if (al) { 1252 + gfs2_inplace_release(ip); 1253 + do_grow_qunlock: 1254 + gfs2_quota_unlock(ip); 1255 + do_grow_alloc_put: 1256 + gfs2_alloc_put(ip); 1257 + } 1124 1258 return error; 1125 1259 } 1126 1260 1127 1261 /** 1128 - * gfs2_truncatei - make a file a given size 1129 - * @ip: the inode 1130 - * @size: the size to make the file 1131 - * @truncator: function to truncate the last partial block 1262 + * gfs2_setattr_size - make a file a given size 1263 + * @inode: the inode 1264 + * @newsize: the size to make the file 1132 1265 * 1133 - * The file size can grow, shrink, or stay the same size. 1266 + * The file size can grow, shrink, or stay the same size. This 1267 + * is called holding i_mutex and an exclusive glock on the inode 1268 + * in question. 1134 1269 * 1135 1270 * Returns: errno 1136 1271 */ 1137 1272 1138 - int gfs2_truncatei(struct gfs2_inode *ip, u64 size) 1273 + int gfs2_setattr_size(struct inode *inode, u64 newsize) 1139 1274 { 1140 - int error; 1275 + int ret; 1276 + u64 oldsize; 1141 1277 1142 - if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode))) 1143 - return -EINVAL; 1278 + BUG_ON(!S_ISREG(inode->i_mode)); 1144 1279 1145 - if (size > ip->i_disksize) 1146 - error = do_grow(ip, size); 1147 - else if (size < ip->i_disksize) 1148 - error = do_shrink(ip, size); 1149 - else 1150 - /* update time stamps */ 1151 - error = do_touch(ip, size); 1280 + ret = inode_newsize_ok(inode, newsize); 1281 + if (ret) 1282 + return ret; 1152 1283 1153 - return error; 1284 + oldsize = inode->i_size; 1285 + if (newsize >= oldsize) 1286 + return do_grow(inode, newsize); 1287 + 1288 + return do_shrink(inode, oldsize, newsize); 1154 1289 } 1155 1290 1156 1291 int gfs2_truncatei_resume(struct gfs2_inode *ip)
+11 -9
fs/gfs2/bmap.h
··· 44 44 } 45 45 } 46 46 47 - int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); 48 - int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create); 49 - int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); 50 - 51 - int gfs2_truncatei(struct gfs2_inode *ip, u64 size); 52 - int gfs2_truncatei_resume(struct gfs2_inode *ip); 53 - int gfs2_file_dealloc(struct gfs2_inode *ip); 54 - int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, 55 - unsigned int len); 47 + extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); 48 + extern int gfs2_block_map(struct inode *inode, sector_t lblock, 49 + struct buffer_head *bh, int create); 50 + extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, 51 + u64 *dblock, unsigned *extlen); 52 + extern int gfs2_setattr_size(struct inode *inode, u64 size); 53 + extern void gfs2_trim_blocks(struct inode *inode); 54 + extern int gfs2_truncatei_resume(struct gfs2_inode *ip); 55 + extern int gfs2_file_dealloc(struct gfs2_inode *ip); 56 + extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, 57 + unsigned int len); 56 58 57 59 #endif /* __BMAP_DOT_H__ */
+1 -25
fs/gfs2/ops_inode.c
··· 1071 1071 return error; 1072 1072 } 1073 1073 1074 - /* 1075 - * XXX(truncate): the truncate_setsize calls should be moved to the end. 1076 - */ 1077 - static int setattr_size(struct inode *inode, struct iattr *attr) 1078 - { 1079 - struct gfs2_inode *ip = GFS2_I(inode); 1080 - struct gfs2_sbd *sdp = GFS2_SB(inode); 1081 - int error; 1082 - 1083 - if (attr->ia_size != ip->i_disksize) { 1084 - error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); 1085 - if (error) 1086 - return error; 1087 - truncate_setsize(inode, attr->ia_size); 1088 - gfs2_trans_end(sdp); 1089 - } 1090 - 1091 - error = gfs2_truncatei(ip, attr->ia_size); 1092 - if (error && (inode->i_size != ip->i_disksize)) 1093 - i_size_write(inode, ip->i_disksize); 1094 - 1095 - return error; 1096 - } 1097 - 1098 1074 static int setattr_chown(struct inode *inode, struct iattr *attr) 1099 1075 { 1100 1076 struct gfs2_inode *ip = GFS2_I(inode); ··· 1171 1195 goto out; 1172 1196 1173 1197 if (attr->ia_valid & ATTR_SIZE) 1174 - error = setattr_size(inode, attr); 1198 + error = gfs2_setattr_size(inode, attr->ia_size); 1175 1199 else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) 1176 1200 error = setattr_chown(inode, attr); 1177 1201 else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))