46
46
47
47
#include <trace/events/ext4.h>
48
48
49
+ static int ext4_split_extent (handle_t * handle ,
50
+ struct inode * inode ,
51
+ struct ext4_ext_path * path ,
52
+ struct ext4_map_blocks * map ,
53
+ int split_flag ,
54
+ int flags );
55
+
49
56
static int ext4_ext_truncate_extend_restart (handle_t * handle ,
50
57
struct inode * inode ,
51
58
int needed )
@@ -2203,8 +2210,16 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
2203
2210
ext4_free_blocks (handle , inode , NULL , start , num , flags );
2204
2211
} else if (from == le32_to_cpu (ex -> ee_block )
2205
2212
&& to <= le32_to_cpu (ex -> ee_block ) + ee_len - 1 ) {
2206
- printk (KERN_INFO "strange request: removal %u-%u from %u:%u\n" ,
2207
- from , to , le32_to_cpu (ex -> ee_block ), ee_len );
2213
+ /* head removal */
2214
+ ext4_lblk_t num ;
2215
+ ext4_fsblk_t start ;
2216
+
2217
+ num = to - from ;
2218
+ start = ext4_ext_pblock (ex );
2219
+
2220
+ ext_debug ("free first %u blocks starting %llu\n" , num , start );
2221
+ ext4_free_blocks (handle , inode , 0 , start , num , flags );
2222
+
2208
2223
} else {
2209
2224
printk (KERN_INFO "strange request: removal(2) "
2210
2225
"%u-%u from %u:%u\n" ,
@@ -2213,9 +2228,22 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
2213
2228
return 0 ;
2214
2229
}
2215
2230
2231
+
2232
+ /*
2233
+ * ext4_ext_rm_leaf() Removes the extents associated with the
2234
+ * blocks appearing between "start" and "end", and splits the extents
2235
+ * if "start" and "end" appear in the same extent
2236
+ *
2237
+ * @handle: The journal handle
2238
+ * @inode: The files inode
2239
+ * @path: The path to the leaf
2240
+ * @start: The first block to remove
2241
+ * @end: The last block to remove
2242
+ */
2216
2243
static int
2217
2244
ext4_ext_rm_leaf (handle_t * handle , struct inode * inode ,
2218
- struct ext4_ext_path * path , ext4_lblk_t start )
2245
+ struct ext4_ext_path * path , ext4_lblk_t start ,
2246
+ ext4_lblk_t end )
2219
2247
{
2220
2248
int err = 0 , correct_index = 0 ;
2221
2249
int depth = ext_depth (inode ), credits ;
@@ -2226,6 +2254,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2226
2254
unsigned short ex_ee_len ;
2227
2255
unsigned uninitialized = 0 ;
2228
2256
struct ext4_extent * ex ;
2257
+ struct ext4_map_blocks map ;
2229
2258
2230
2259
/* the header must be checked already in ext4_ext_remove_space() */
2231
2260
ext_debug ("truncate since %u in leaf\n" , start );
@@ -2255,31 +2284,95 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2255
2284
path [depth ].p_ext = ex ;
2256
2285
2257
2286
a = ex_ee_block > start ? ex_ee_block : start ;
2258
- b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ?
2259
- ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK ;
2287
+ b = ex_ee_block + ex_ee_len - 1 < end ?
2288
+ ex_ee_block + ex_ee_len - 1 : end ;
2260
2289
2261
2290
ext_debug (" border %u:%u\n" , a , b );
2262
2291
2263
- if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1 ) {
2264
- block = 0 ;
2265
- num = 0 ;
2266
- BUG ();
2292
+ /* If this extent is beyond the end of the hole, skip it */
2293
+ if (end <= ex_ee_block ) {
2294
+ ex -- ;
2295
+ ex_ee_block = le32_to_cpu (ex -> ee_block );
2296
+ ex_ee_len = ext4_ext_get_actual_len (ex );
2297
+ continue ;
2298
+ } else if (a != ex_ee_block &&
2299
+ b != ex_ee_block + ex_ee_len - 1 ) {
2300
+ /*
2301
+ * If this is a truncate, then this condition should
2302
+ * never happen because at least one of the end points
2303
+ * needs to be on the edge of the extent.
2304
+ */
2305
+ if (end == EXT_MAX_BLOCK ) {
2306
+ ext_debug (" bad truncate %u:%u\n" ,
2307
+ start , end );
2308
+ block = 0 ;
2309
+ num = 0 ;
2310
+ err = - EIO ;
2311
+ goto out ;
2312
+ }
2313
+ /*
2314
+ * else this is a hole punch, so the extent needs to
2315
+ * be split since neither edge of the hole is on the
2316
+ * extent edge
2317
+ */
2318
+ else {
2319
+ map .m_pblk = ext4_ext_pblock (ex );
2320
+ map .m_lblk = ex_ee_block ;
2321
+ map .m_len = b - ex_ee_block ;
2322
+
2323
+ err = ext4_split_extent (handle ,
2324
+ inode , path , & map , 0 ,
2325
+ EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
2326
+ EXT4_GET_BLOCKS_PRE_IO );
2327
+
2328
+ if (err < 0 )
2329
+ goto out ;
2330
+
2331
+ ex_ee_len = ext4_ext_get_actual_len (ex );
2332
+
2333
+ b = ex_ee_block + ex_ee_len - 1 < end ?
2334
+ ex_ee_block + ex_ee_len - 1 : end ;
2335
+
2336
+ /* Then remove tail of this extent */
2337
+ block = ex_ee_block ;
2338
+ num = a - block ;
2339
+ }
2267
2340
} else if (a != ex_ee_block ) {
2268
2341
/* remove tail of the extent */
2269
2342
block = ex_ee_block ;
2270
2343
num = a - block ;
2271
2344
} else if (b != ex_ee_block + ex_ee_len - 1 ) {
2272
2345
/* remove head of the extent */
2273
- block = a ;
2274
- num = b - a ;
2275
- /* there is no "make a hole" API yet */
2276
- BUG ();
2346
+ block = b ;
2347
+ num = ex_ee_block + ex_ee_len - b ;
2348
+
2349
+ /*
2350
+ * If this is a truncate, this condition
2351
+ * should never happen
2352
+ */
2353
+ if (end == EXT_MAX_BLOCK ) {
2354
+ ext_debug (" bad truncate %u:%u\n" ,
2355
+ start , end );
2356
+ err = - EIO ;
2357
+ goto out ;
2358
+ }
2277
2359
} else {
2278
2360
/* remove whole extent: excellent! */
2279
2361
block = ex_ee_block ;
2280
2362
num = 0 ;
2281
- BUG_ON (a != ex_ee_block );
2282
- BUG_ON (b != ex_ee_block + ex_ee_len - 1 );
2363
+ if (a != ex_ee_block ) {
2364
+ ext_debug (" bad truncate %u:%u\n" ,
2365
+ start , end );
2366
+ err = - EIO ;
2367
+ goto out ;
2368
+ }
2369
+
2370
+ if (b != ex_ee_block + ex_ee_len - 1 ) {
2371
+ ext_debug (" bad truncate %u:%u\n" ,
2372
+ start , end );
2373
+ err = - EIO ;
2374
+ goto out ;
2375
+ }
2283
2376
}
2284
2377
2285
2378
/*
@@ -2310,7 +2403,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2310
2403
if (num == 0 ) {
2311
2404
/* this extent is removed; mark slot entirely unused */
2312
2405
ext4_ext_store_pblock (ex , 0 );
2313
- le16_add_cpu (& eh -> eh_entries , -1 );
2406
+ } else if (block != ex_ee_block ) {
2407
+ /*
2408
+ * If this was a head removal, then we need to update
2409
+ * the physical block since it is now at a different
2410
+ * location
2411
+ */
2412
+ ext4_ext_store_pblock (ex , ext4_ext_pblock (ex ) + (b - a ));
2314
2413
}
2315
2414
2316
2415
ex -> ee_block = cpu_to_le32 (block );
@@ -2326,6 +2425,27 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2326
2425
if (err )
2327
2426
goto out ;
2328
2427
2428
+ /*
2429
+ * If the extent was completely released,
2430
+ * we need to remove it from the leaf
2431
+ */
2432
+ if (num == 0 ) {
2433
+ if (end != EXT_MAX_BLOCK ) {
2434
+ /*
2435
+ * For hole punching, we need to scoot all the
2436
+ * extents up when an extent is removed so that
2437
+ * we dont have blank extents in the middle
2438
+ */
2439
+ memmove (ex , ex + 1 , (EXT_LAST_EXTENT (eh ) - ex ) *
2440
+ sizeof (struct ext4_extent ));
2441
+
2442
+ /* Now get rid of the one at the end */
2443
+ memset (EXT_LAST_EXTENT (eh ), 0 ,
2444
+ sizeof (struct ext4_extent ));
2445
+ }
2446
+ le16_add_cpu (& eh -> eh_entries , -1 );
2447
+ }
2448
+
2329
2449
ext_debug ("new extent: %u:%u:%llu\n" , block , num ,
2330
2450
ext4_ext_pblock (ex ));
2331
2451
ex -- ;
@@ -2366,7 +2486,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
2366
2486
return 1 ;
2367
2487
}
2368
2488
2369
- static int ext4_ext_remove_space (struct inode * inode , ext4_lblk_t start )
2489
+ static int ext4_ext_remove_space (struct inode * inode , ext4_lblk_t start ,
2490
+ ext4_lblk_t end )
2370
2491
{
2371
2492
struct super_block * sb = inode -> i_sb ;
2372
2493
int depth = ext_depth (inode );
@@ -2405,7 +2526,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
2405
2526
while (i >= 0 && err == 0 ) {
2406
2527
if (i == depth ) {
2407
2528
/* this is leaf block */
2408
- err = ext4_ext_rm_leaf (handle , inode , path , start );
2529
+ err = ext4_ext_rm_leaf (handle , inode , path ,
2530
+ start , end );
2409
2531
/* root level has p_bh == NULL, brelse() eats this */
2410
2532
brelse (path [i ].p_bh );
2411
2533
path [i ].p_bh = NULL ;
@@ -3451,7 +3573,7 @@ void ext4_ext_truncate(struct inode *inode)
3451
3573
3452
3574
last_block = (inode -> i_size + sb -> s_blocksize - 1 )
3453
3575
>> EXT4_BLOCK_SIZE_BITS (sb );
3454
- err = ext4_ext_remove_space (inode , last_block );
3576
+ err = ext4_ext_remove_space (inode , last_block , EXT_MAX_BLOCK );
3455
3577
3456
3578
/* In a multi-transaction truncate, we only make the final
3457
3579
* transaction synchronous.
0 commit comments