aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_bmap_util.c252
1 files changed, 137 insertions, 115 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 586bb64e674b..e36664fc5715 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1184,30 +1184,132 @@ xfs_zero_remaining_bytes(
1184 return error; 1184 return error;
1185} 1185}
1186 1186
1187static int
1188xfs_unmap_extent(
1189 struct xfs_inode *ip,
1190 xfs_fileoff_t startoffset_fsb,
1191 xfs_filblks_t len_fsb,
1192 int *done)
1193{
1194 struct xfs_mount *mp = ip->i_mount;
1195 struct xfs_trans *tp;
1196 struct xfs_bmap_free free_list;
1197 xfs_fsblock_t firstfsb;
1198 uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
1199 int error;
1200
1201 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
1202 if (error) {
1203 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1204 return error;
1205 }
1206
1207 xfs_ilock(ip, XFS_ILOCK_EXCL);
1208 error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot,
1209 ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS);
1210 if (error)
1211 goto out_trans_cancel;
1212
1213 xfs_trans_ijoin(tp, ip, 0);
1214
1215 xfs_bmap_init(&free_list, &firstfsb);
1216 error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb,
1217 &free_list, done);
1218 if (error)
1219 goto out_bmap_cancel;
1220
1221 error = xfs_bmap_finish(&tp, &free_list, NULL);
1222 if (error)
1223 goto out_bmap_cancel;
1224
1225 error = xfs_trans_commit(tp);
1226out_unlock:
1227 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1228 return error;
1229
1230out_bmap_cancel:
1231 xfs_bmap_cancel(&free_list);
1232out_trans_cancel:
1233 xfs_trans_cancel(tp);
1234 goto out_unlock;
1235}
1236
1237static int
1238xfs_adjust_extent_unmap_boundaries(
1239 struct xfs_inode *ip,
1240 xfs_fileoff_t *startoffset_fsb,
1241 xfs_fileoff_t *endoffset_fsb)
1242{
1243 struct xfs_mount *mp = ip->i_mount;
1244 struct xfs_bmbt_irec imap;
1245 int nimap, error;
1246 xfs_extlen_t mod = 0;
1247
1248 nimap = 1;
1249 error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0);
1250 if (error)
1251 return error;
1252
1253 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1254 xfs_daddr_t block;
1255
1256 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1257 block = imap.br_startblock;
1258 mod = do_div(block, mp->m_sb.sb_rextsize);
1259 if (mod)
1260 *startoffset_fsb += mp->m_sb.sb_rextsize - mod;
1261 }
1262
1263 nimap = 1;
1264 error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0);
1265 if (error)
1266 return error;
1267
1268 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1269 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1270 mod++;
1271 if (mod && mod != mp->m_sb.sb_rextsize)
1272 *endoffset_fsb -= mod;
1273 }
1274
1275 return 0;
1276}
1277
1278static int
1279xfs_flush_unmap_range(
1280 struct xfs_inode *ip,
1281 xfs_off_t offset,
1282 xfs_off_t len)
1283{
1284 struct xfs_mount *mp = ip->i_mount;
1285 struct inode *inode = VFS_I(ip);
1286 xfs_off_t rounding, start, end;
1287 int error;
1288
1289 /* wait for the completion of any pending DIOs */
1290 inode_dio_wait(inode);
1291
1292 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE);
1293 start = round_down(offset, rounding);
1294 end = round_up(offset + len, rounding) - 1;
1295
1296 error = filemap_write_and_wait_range(inode->i_mapping, start, end);
1297 if (error)
1298 return error;
1299 truncate_pagecache_range(inode, start, end);
1300 return 0;
1301}
1302
1187int 1303int
1188xfs_free_file_space( 1304xfs_free_file_space(
1189 struct xfs_inode *ip, 1305 struct xfs_inode *ip,
1190 xfs_off_t offset, 1306 xfs_off_t offset,
1191 xfs_off_t len) 1307 xfs_off_t len)
1192{ 1308{
1193 int done; 1309 struct xfs_mount *mp = ip->i_mount;
1194 xfs_fileoff_t endoffset_fsb;
1195 int error;
1196 xfs_fsblock_t firstfsb;
1197 xfs_bmap_free_t free_list;
1198 xfs_bmbt_irec_t imap;
1199 xfs_off_t ioffset;
1200 xfs_off_t iendoffset;
1201 xfs_extlen_t mod=0;
1202 xfs_mount_t *mp;
1203 int nimap;
1204 uint resblks;
1205 xfs_off_t rounding;
1206 int rt;
1207 xfs_fileoff_t startoffset_fsb; 1310 xfs_fileoff_t startoffset_fsb;
1208 xfs_trans_t *tp; 1311 xfs_fileoff_t endoffset_fsb;
1209 1312 int done, error;
1210 mp = ip->i_mount;
1211 1313
1212 trace_xfs_free_file_space(ip); 1314 trace_xfs_free_file_space(ip);
1213 1315
@@ -1215,60 +1317,30 @@ xfs_free_file_space(
1215 if (error) 1317 if (error)
1216 return error; 1318 return error;
1217 1319
1218 error = 0;
1219 if (len <= 0) /* if nothing being freed */ 1320 if (len <= 0) /* if nothing being freed */
1220 return error; 1321 return 0;
1221 rt = XFS_IS_REALTIME_INODE(ip);
1222 startoffset_fsb = XFS_B_TO_FSB(mp, offset);
1223 endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
1224
1225 /* wait for the completion of any pending DIOs */
1226 inode_dio_wait(VFS_I(ip));
1227 1322
1228 rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); 1323 error = xfs_flush_unmap_range(ip, offset, len);
1229 ioffset = round_down(offset, rounding);
1230 iendoffset = round_up(offset + len, rounding) - 1;
1231 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset,
1232 iendoffset);
1233 if (error) 1324 if (error)
1234 goto out; 1325 return error;
1235 truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset); 1326
1327 startoffset_fsb = XFS_B_TO_FSB(mp, offset);
1328 endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
1236 1329
1237 /* 1330 /*
1238 * Need to zero the stuff we're not freeing, on disk. 1331 * Need to zero the stuff we're not freeing, on disk. If it's a RT file
1239 * If it's a realtime file & can't use unwritten extents then we 1332 * and we can't use unwritten extents then we actually need to ensure
1240 * actually need to zero the extent edges. Otherwise xfs_bunmapi 1333 * to zero the whole extent, otherwise we just need to take of block
1241 * will take care of it for us. 1334 * boundaries, and xfs_bunmapi will handle the rest.
1242 */ 1335 */
1243 if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { 1336 if (XFS_IS_REALTIME_INODE(ip) &&
1244 nimap = 1; 1337 !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
1245 error = xfs_bmapi_read(ip, startoffset_fsb, 1, 1338 error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb,
1246 &imap, &nimap, 0); 1339 &endoffset_fsb);
1247 if (error) 1340 if (error)
1248 goto out; 1341 return error;
1249 ASSERT(nimap == 0 || nimap == 1);
1250 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1251 xfs_daddr_t block;
1252
1253 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1254 block = imap.br_startblock;
1255 mod = do_div(block, mp->m_sb.sb_rextsize);
1256 if (mod)
1257 startoffset_fsb += mp->m_sb.sb_rextsize - mod;
1258 }
1259 nimap = 1;
1260 error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
1261 &imap, &nimap, 0);
1262 if (error)
1263 goto out;
1264 ASSERT(nimap == 0 || nimap == 1);
1265 if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
1266 ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
1267 mod++;
1268 if (mod && (mod != mp->m_sb.sb_rextsize))
1269 endoffset_fsb -= mod;
1270 }
1271 } 1342 }
1343
1272 if ((done = (endoffset_fsb <= startoffset_fsb))) 1344 if ((done = (endoffset_fsb <= startoffset_fsb)))
1273 /* 1345 /*
1274 * One contiguous piece to clear 1346 * One contiguous piece to clear
@@ -1288,62 +1360,12 @@ xfs_free_file_space(
1288 offset + len - 1); 1360 offset + len - 1);
1289 } 1361 }
1290 1362
1291 /*
1292 * free file space until done or until there is an error
1293 */
1294 resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
1295 while (!error && !done) { 1363 while (!error && !done) {
1296 1364 error = xfs_unmap_extent(ip, startoffset_fsb,
1297 /* 1365 endoffset_fsb - startoffset_fsb, &done);
1298 * allocate and setup the transaction. Allow this
1299 * transaction to dip into the reserve blocks to ensure
1300 * the freeing of the space succeeds at ENOSPC.
1301 */
1302 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0,
1303 &tp);
1304 if (error) {
1305 ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
1306 break;
1307 }
1308 xfs_ilock(ip, XFS_ILOCK_EXCL);
1309 error = xfs_trans_reserve_quota(tp, mp,
1310 ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
1311 resblks, 0, XFS_QMOPT_RES_REGBLKS);
1312 if (error)
1313 goto error1;
1314
1315 xfs_trans_ijoin(tp, ip, 0);
1316
1317 /*
1318 * issue the bunmapi() call to free the blocks
1319 */
1320 xfs_bmap_init(&free_list, &firstfsb);
1321 error = xfs_bunmapi(tp, ip, startoffset_fsb,
1322 endoffset_fsb - startoffset_fsb,
1323 0, 2, &firstfsb, &free_list, &done);
1324 if (error)
1325 goto error0;
1326
1327 /*
1328 * complete the transaction
1329 */
1330 error = xfs_bmap_finish(&tp, &free_list, NULL);
1331 if (error)
1332 goto error0;
1333
1334 error = xfs_trans_commit(tp);
1335 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1336 } 1366 }
1337 1367
1338 out:
1339 return error; 1368 return error;
1340
1341 error0:
1342 xfs_bmap_cancel(&free_list);
1343 error1:
1344 xfs_trans_cancel(tp);
1345 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1346 goto out;
1347} 1369}
1348 1370
1349/* 1371/*