diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 252 |
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 | ||
1187 | static int | ||
1188 | xfs_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); | ||
1226 | out_unlock: | ||
1227 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1228 | return error; | ||
1229 | |||
1230 | out_bmap_cancel: | ||
1231 | xfs_bmap_cancel(&free_list); | ||
1232 | out_trans_cancel: | ||
1233 | xfs_trans_cancel(tp); | ||
1234 | goto out_unlock; | ||
1235 | } | ||
1236 | |||
1237 | static int | ||
1238 | xfs_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 | |||
1278 | static int | ||
1279 | xfs_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 | |||
1187 | int | 1303 | int |
1188 | xfs_free_file_space( | 1304 | xfs_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 | /* |