aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r--fs/xfs/xfs_bmap_util.c343
1 files changed, 130 insertions, 213 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 28c42fb0c12a..91bee2db3207 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1087,99 +1087,120 @@ error1: /* Just cancel transaction */
1087 return error; 1087 return error;
1088} 1088}
1089 1089
1090/* 1090static int
1091 * Zero file bytes between startoff and endoff inclusive. 1091xfs_unmap_extent(
1092 * The iolock is held exclusive and no blocks are buffered. 1092 struct xfs_inode *ip,
1093 * 1093 xfs_fileoff_t startoffset_fsb,
1094 * This function is used by xfs_free_file_space() to zero 1094 xfs_filblks_t len_fsb,
1095 * partial blocks when the range to free is not block aligned. 1095 int *done)
1096 * When unreserving space with boundaries that are not block
1097 * aligned we round up the start and round down the end
1098 * boundaries and then use this function to zero the parts of
1099 * the blocks that got dropped during the rounding.
1100 */
1101STATIC int
1102xfs_zero_remaining_bytes(
1103 xfs_inode_t *ip,
1104 xfs_off_t startoff,
1105 xfs_off_t endoff)
1106{ 1096{
1107 xfs_bmbt_irec_t imap; 1097 struct xfs_mount *mp = ip->i_mount;
1108 xfs_fileoff_t offset_fsb; 1098 struct xfs_trans *tp;
1109 xfs_off_t lastoffset; 1099 struct xfs_bmap_free free_list;
1110 xfs_off_t offset; 1100 xfs_fsblock_t firstfsb;
1111 xfs_buf_t *bp; 1101 uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
1112 xfs_mount_t *mp = ip->i_mount; 1102 int error;
1113 int nimap;
1114 int error = 0;
1115 1103
1116 /* 1104 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
1117 * Avoid doing I/O beyond eof - it's not necessary 1105 if (error) {
1118 * since nothing can read beyond eof. The space will 1106 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1119 * be zeroed when the file is extended anyway. 1107 return error;
1120 */ 1108 }
1121 if (startoff >= XFS_ISIZE(ip))
1122 return 0;
1123 1109
1124 if (endoff > XFS_ISIZE(ip)) 1110 xfs_ilock(ip, XFS_ILOCK_EXCL);
1125 endoff = XFS_ISIZE(ip); 1111 error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot,
1112 ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS);
1113 if (error)
1114 goto out_trans_cancel;
1126 1115
1127 for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { 1116 xfs_trans_ijoin(tp, ip, 0);
1128 uint lock_mode;
1129 1117
1130 offset_fsb = XFS_B_TO_FSBT(mp, offset); 1118 xfs_bmap_init(&free_list, &firstfsb);
1131 nimap = 1; 1119 error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb,
1120 &free_list, done);
1121 if (error)
1122 goto out_bmap_cancel;
1132 1123
1133 lock_mode = xfs_ilock_data_map_shared(ip); 1124 error = xfs_bmap_finish(&tp, &free_list, NULL);
1134 error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0); 1125 if (error)
1135 xfs_iunlock(ip, lock_mode); 1126 goto out_bmap_cancel;
1136 1127
1137 if (error || nimap < 1) 1128 error = xfs_trans_commit(tp);
1138 break; 1129out_unlock:
1139 ASSERT(imap.br_blockcount >= 1); 1130 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1140 ASSERT(imap.br_startoff == offset_fsb); 1131 return error;
1141 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1142 1132
1143 if (imap.br_startblock == HOLESTARTBLOCK || 1133out_bmap_cancel:
1144 imap.br_state == XFS_EXT_UNWRITTEN) { 1134 xfs_bmap_cancel(&free_list);
1145 /* skip the entire extent */ 1135out_trans_cancel:
1146 lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1136 xfs_trans_cancel(tp);
1147 imap.br_blockcount) - 1; 1137 goto out_unlock;
1148 continue; 1138}
1149 }
1150 1139
1151 lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1; 1140static int
1152 if (lastoffset > endoff) 1141xfs_adjust_extent_unmap_boundaries(
1153 lastoffset = endoff; 1142 struct xfs_inode *ip,
1143 xfs_fileoff_t *startoffset_fsb,
1144 xfs_fileoff_t *endoffset_fsb)
1145{
1146 struct xfs_mount *mp = ip->i_mount;
1147 struct xfs_bmbt_irec imap;
1148 int nimap, error;
1149 xfs_extlen_t mod = 0;
1154 1150
1155 /* DAX can just zero the backing device directly */ 1151 nimap = 1;
1156 if (IS_DAX(VFS_I(ip))) { 1152 error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0);
1157 error = dax_zero_page_range(VFS_I(ip), offset, 1153 if (error)
1158 lastoffset - offset + 1, 1154 return error;
1159 xfs_get_blocks_direct);
1160 if (error)
1161 return error;
1162 continue;
1163 }
1164 1155
1165 error = xfs_buf_read_uncached(XFS_IS_REALTIME_INODE(ip) ? 1156 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1166 mp->m_rtdev_targp : mp->m_ddev_targp, 1157 xfs_daddr_t block;
1167 xfs_fsb_to_db(ip, imap.br_startblock),
1168 BTOBB(mp->m_sb.sb_blocksize),
1169 0, &bp, NULL);
1170 if (error)
1171 return error;
1172 1158
1173 memset(bp->b_addr + 1159 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1174 (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), 1160 block = imap.br_startblock;
1175 0, lastoffset - offset + 1); 1161 mod = do_div(block, mp->m_sb.sb_rextsize);
1162 if (mod)
1163 *startoffset_fsb += mp->m_sb.sb_rextsize - mod;
1164 }
1176 1165
1177 error = xfs_bwrite(bp); 1166 nimap = 1;
1178 xfs_buf_relse(bp); 1167 error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0);
1179 if (error) 1168 if (error)
1180 return error; 1169 return error;
1170
1171 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1172 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1173 mod++;
1174 if (mod && mod != mp->m_sb.sb_rextsize)
1175 *endoffset_fsb -= mod;
1181 } 1176 }
1182 return error; 1177
1178 return 0;
1179}
1180
1181static int
1182xfs_flush_unmap_range(
1183 struct xfs_inode *ip,
1184 xfs_off_t offset,
1185 xfs_off_t len)
1186{
1187 struct xfs_mount *mp = ip->i_mount;
1188 struct inode *inode = VFS_I(ip);
1189 xfs_off_t rounding, start, end;
1190 int error;
1191
1192 /* wait for the completion of any pending DIOs */
1193 inode_dio_wait(inode);
1194
1195 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE);
1196 start = round_down(offset, rounding);
1197 end = round_up(offset + len, rounding) - 1;
1198
1199 error = filemap_write_and_wait_range(inode->i_mapping, start, end);
1200 if (error)
1201 return error;
1202 truncate_pagecache_range(inode, start, end);
1203 return 0;
1183} 1204}
1184 1205
1185int 1206int
@@ -1188,24 +1209,10 @@ xfs_free_file_space(
1188 xfs_off_t offset, 1209 xfs_off_t offset,
1189 xfs_off_t len) 1210 xfs_off_t len)
1190{ 1211{
1191 int done; 1212 struct xfs_mount *mp = ip->i_mount;
1192 xfs_fileoff_t endoffset_fsb;
1193 int error;
1194 xfs_fsblock_t firstfsb;
1195 xfs_bmap_free_t free_list;
1196 xfs_bmbt_irec_t imap;
1197 xfs_off_t ioffset;
1198 xfs_off_t iendoffset;
1199 xfs_extlen_t mod=0;
1200 xfs_mount_t *mp;
1201 int nimap;
1202 uint resblks;
1203 xfs_off_t rounding;
1204 int rt;
1205 xfs_fileoff_t startoffset_fsb; 1213 xfs_fileoff_t startoffset_fsb;
1206 xfs_trans_t *tp; 1214 xfs_fileoff_t endoffset_fsb;
1207 1215 int done = 0, error;
1208 mp = ip->i_mount;
1209 1216
1210 trace_xfs_free_file_space(ip); 1217 trace_xfs_free_file_space(ip);
1211 1218
@@ -1213,135 +1220,45 @@ xfs_free_file_space(
1213 if (error) 1220 if (error)
1214 return error; 1221 return error;
1215 1222
1216 error = 0;
1217 if (len <= 0) /* if nothing being freed */ 1223 if (len <= 0) /* if nothing being freed */
1218 return error; 1224 return 0;
1219 rt = XFS_IS_REALTIME_INODE(ip);
1220 startoffset_fsb = XFS_B_TO_FSB(mp, offset);
1221 endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
1222
1223 /* wait for the completion of any pending DIOs */
1224 inode_dio_wait(VFS_I(ip));
1225 1225
1226 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); 1226 error = xfs_flush_unmap_range(ip, offset, len);
1227 ioffset = round_down(offset, rounding);
1228 iendoffset = round_up(offset + len, rounding) - 1;
1229 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset,
1230 iendoffset);
1231 if (error) 1227 if (error)
1232 goto out; 1228 return error;
1233 truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset); 1229
1230 startoffset_fsb = XFS_B_TO_FSB(mp, offset);
1231 endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
1234 1232
1235 /* 1233 /*
1236 * Need to zero the stuff we're not freeing, on disk. 1234 * Need to zero the stuff we're not freeing, on disk. If it's a RT file
1237 * If it's a realtime file & can't use unwritten extents then we 1235 * and we can't use unwritten extents then we actually need to ensure
1238 * actually need to zero the extent edges. Otherwise xfs_bunmapi 1236 * to zero the whole extent, otherwise we just need to take of block
1239 * will take care of it for us. 1237 * boundaries, and xfs_bunmapi will handle the rest.
1240 */ 1238 */
1241 if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { 1239 if (XFS_IS_REALTIME_INODE(ip) &&
1242 nimap = 1; 1240 !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
1243 error = xfs_bmapi_read(ip, startoffset_fsb, 1, 1241 error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb,
1244 &imap, &nimap, 0); 1242 &endoffset_fsb);
1245 if (error) 1243 if (error)
1246 goto out; 1244 return error;
1247 ASSERT(nimap == 0 || nimap == 1);
1248 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1249 xfs_daddr_t block;
1250
1251 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1252 block = imap.br_startblock;
1253 mod = do_div(block, mp->m_sb.sb_rextsize);
1254 if (mod)
1255 startoffset_fsb += mp->m_sb.sb_rextsize - mod;
1256 }
1257 nimap = 1;
1258 error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
1259 &imap, &nimap, 0);
1260 if (error)
1261 goto out;
1262 ASSERT(nimap == 0 || nimap == 1);
1263 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1264 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1265 mod++;
1266 if (mod && (mod != mp->m_sb.sb_rextsize))
1267 endoffset_fsb -= mod;
1268 }
1269 }
1270 if ((done = (endoffset_fsb <= startoffset_fsb)))
1271 /*
1272 * One contiguous piece to clear
1273 */
1274 error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1);
1275 else {
1276 /*
1277 * Some full blocks, possibly two pieces to clear
1278 */
1279 if (offset < XFS_FSB_TO_B(mp, startoffset_fsb))
1280 error = xfs_zero_remaining_bytes(ip, offset,
1281 XFS_FSB_TO_B(mp, startoffset_fsb) - 1);
1282 if (!error &&
1283 XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len)
1284 error = xfs_zero_remaining_bytes(ip,
1285 XFS_FSB_TO_B(mp, endoffset_fsb),
1286 offset + len - 1);
1287 } 1245 }
1288 1246
1289 /* 1247 if (endoffset_fsb > startoffset_fsb) {
1290 * free file space until done or until there is an error 1248 while (!done) {
1291 */ 1249 error = xfs_unmap_extent(ip, startoffset_fsb,
1292 resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); 1250 endoffset_fsb - startoffset_fsb, &done);
1293 while (!error && !done) { 1251 if (error)
1294 1252 return error;
1295 /*
1296 * allocate and setup the transaction. Allow this
1297 * transaction to dip into the reserve blocks to ensure
1298 * the freeing of the space succeeds at ENOSPC.
1299 */
1300 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0,
1301 &tp);
1302 if (error) {
1303 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1304 break;
1305 } 1253 }
1306 xfs_ilock(ip, XFS_ILOCK_EXCL);
1307 error = xfs_trans_reserve_quota(tp, mp,
1308 ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
1309 resblks, 0, XFS_QMOPT_RES_REGBLKS);
1310 if (error)
1311 goto error1;
1312
1313 xfs_trans_ijoin(tp, ip, 0);
1314
1315 /*
1316 * issue the bunmapi() call to free the blocks
1317 */
1318 xfs_bmap_init(&free_list, &firstfsb);
1319 error = xfs_bunmapi(tp, ip, startoffset_fsb,
1320 endoffset_fsb - startoffset_fsb,
1321 0, 2, &firstfsb, &free_list, &done);
1322 if (error)
1323 goto error0;
1324
1325 /*
1326 * complete the transaction
1327 */
1328 error = xfs_bmap_finish(&tp, &free_list, NULL);
1329 if (error)
1330 goto error0;
1331
1332 error = xfs_trans_commit(tp);
1333 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1334 } 1254 }
1335 1255
1336 out: 1256 /*
1337 return error; 1257 * Now that we've unmap all full blocks we'll have to zero out any
1338 1258 * partial block at the beginning and/or end. xfs_zero_range is
1339 error0: 1259 * smart enough to skip any holes, including those we just created.
1340 xfs_bmap_cancel(&free_list); 1260 */
1341 error1: 1261 return xfs_zero_range(ip, offset, len, NULL);
1342 xfs_trans_cancel(tp);
1343 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1344 goto out;
1345} 1262}
1346 1263
1347/* 1264/*