@@ -1353,15 +1353,19 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1353
1353
size_t min_offs , free ;
1354
1354
int total_ino ;
1355
1355
void * base , * start , * end ;
1356
- int extra_isize = 0 , error = 0 , tried_min_extra_isize = 0 ;
1356
+ int error = 0 , tried_min_extra_isize = 0 ;
1357
1357
int s_min_extra_isize = le16_to_cpu (EXT4_SB (inode -> i_sb )-> s_es -> s_min_extra_isize );
1358
+ int isize_diff ; /* How much do we need to grow i_extra_isize */
1358
1359
1359
1360
down_write (& EXT4_I (inode )-> xattr_sem );
1361
+ /*
1362
+ * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty
1363
+ */
1364
+ ext4_set_inode_state (inode , EXT4_STATE_NO_EXPAND );
1360
1365
retry :
1361
- if (EXT4_I (inode )-> i_extra_isize >= new_extra_isize ) {
1362
- up_write (& EXT4_I (inode )-> xattr_sem );
1363
- return 0 ;
1364
- }
1366
+ isize_diff = new_extra_isize - EXT4_I (inode )-> i_extra_isize ;
1367
+ if (EXT4_I (inode )-> i_extra_isize >= new_extra_isize )
1368
+ goto out ;
1365
1369
1366
1370
header = IHDR (inode , raw_inode );
1367
1371
entry = IFIRST (header );
@@ -1382,16 +1386,15 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1382
1386
goto cleanup ;
1383
1387
1384
1388
free = ext4_xattr_free_space (last , & min_offs , base , & total_ino );
1385
- if (free >= new_extra_isize ) {
1389
+ if (free >= isize_diff ) {
1386
1390
entry = IFIRST (header );
1387
1391
ext4_xattr_shift_entries (entry , EXT4_I (inode )-> i_extra_isize
1388
1392
- new_extra_isize , (void * )raw_inode +
1389
1393
EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize ,
1390
1394
(void * )header , total_ino ,
1391
1395
inode -> i_sb -> s_blocksize );
1392
1396
EXT4_I (inode )-> i_extra_isize = new_extra_isize ;
1393
- error = 0 ;
1394
- goto cleanup ;
1397
+ goto out ;
1395
1398
}
1396
1399
1397
1400
/*
@@ -1414,7 +1417,7 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1414
1417
end = bh -> b_data + bh -> b_size ;
1415
1418
min_offs = end - base ;
1416
1419
free = ext4_xattr_free_space (first , & min_offs , base , NULL );
1417
- if (free < new_extra_isize ) {
1420
+ if (free < isize_diff ) {
1418
1421
if (!tried_min_extra_isize && s_min_extra_isize ) {
1419
1422
tried_min_extra_isize ++ ;
1420
1423
new_extra_isize = s_min_extra_isize ;
@@ -1428,7 +1431,7 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1428
1431
free = inode -> i_sb -> s_blocksize ;
1429
1432
}
1430
1433
1431
- while (new_extra_isize > 0 ) {
1434
+ while (isize_diff > 0 ) {
1432
1435
size_t offs , size , entry_size ;
1433
1436
struct ext4_xattr_entry * small_entry = NULL ;
1434
1437
struct ext4_xattr_info i = {
@@ -1459,7 +1462,7 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1459
1462
EXT4_XATTR_SIZE (le32_to_cpu (last -> e_value_size )) +
1460
1463
EXT4_XATTR_LEN (last -> e_name_len );
1461
1464
if (total_size <= free && total_size < min_total_size ) {
1462
- if (total_size < new_extra_isize ) {
1465
+ if (total_size < isize_diff ) {
1463
1466
small_entry = last ;
1464
1467
} else {
1465
1468
entry = last ;
@@ -1514,22 +1517,22 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1514
1517
error = ext4_xattr_ibody_set (handle , inode , & i , is );
1515
1518
if (error )
1516
1519
goto cleanup ;
1520
+ total_ino -= entry_size ;
1517
1521
1518
1522
entry = IFIRST (header );
1519
- if (entry_size + EXT4_XATTR_SIZE (size ) >= new_extra_isize )
1520
- shift_bytes = new_extra_isize ;
1523
+ if (entry_size + EXT4_XATTR_SIZE (size ) >= isize_diff )
1524
+ shift_bytes = isize_diff ;
1521
1525
else
1522
- shift_bytes = entry_size + size ;
1526
+ shift_bytes = entry_size + EXT4_XATTR_SIZE ( size ) ;
1523
1527
/* Adjust the offsets and shift the remaining entries ahead */
1524
- ext4_xattr_shift_entries (entry , EXT4_I (inode )-> i_extra_isize -
1525
- shift_bytes , (void * )raw_inode +
1526
- EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes ,
1527
- (void * )header , total_ino - entry_size ,
1528
- inode -> i_sb -> s_blocksize );
1528
+ ext4_xattr_shift_entries (entry , - shift_bytes ,
1529
+ (void * )raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
1530
+ EXT4_I (inode )-> i_extra_isize + shift_bytes ,
1531
+ (void * )header , total_ino , inode -> i_sb -> s_blocksize );
1529
1532
1530
- extra_isize + = shift_bytes ;
1531
- new_extra_isize - = shift_bytes ;
1532
- EXT4_I ( inode ) -> i_extra_isize = extra_isize ;
1533
+ isize_diff - = shift_bytes ;
1534
+ EXT4_I ( inode ) -> i_extra_isize + = shift_bytes ;
1535
+ header = IHDR ( inode , raw_inode ) ;
1533
1536
1534
1537
i .name = b_entry_name ;
1535
1538
i .value = buffer ;
@@ -1551,6 +1554,8 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1551
1554
kfree (bs );
1552
1555
}
1553
1556
brelse (bh );
1557
+ out :
1558
+ ext4_clear_inode_state (inode , EXT4_STATE_NO_EXPAND );
1554
1559
up_write (& EXT4_I (inode )-> xattr_sem );
1555
1560
return 0 ;
1556
1561
@@ -1562,6 +1567,10 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1562
1567
kfree (is );
1563
1568
kfree (bs );
1564
1569
brelse (bh );
1570
+ /*
1571
+ * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
1572
+ * size expansion failed.
1573
+ */
1565
1574
up_write (& EXT4_I (inode )-> xattr_sem );
1566
1575
return error ;
1567
1576
}
0 commit comments