diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2009-06-05 01:00:26 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-06-05 01:00:26 -0400 |
commit | 1938a150c25bf7c2c47182e753a1038945b70b0e (patch) | |
tree | cab711b2868d719c6f460a75387acf84f6b37576 /fs/ext4/inode.c | |
parent | b31e15527a9bb71b6a11a425d17ce139a62f5af5 (diff) |
ext4: Avoid leaking blocks after a block allocation failure
We should add inode to the orphan list in the same transaction
as block allocation. This ensures that if we crash after a failed
block allocation and before we do a vmtruncate we don't leak block
(ie block marked as used in bitmap but not claimed by the inode).
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
CC: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 17ed0d244dbb..8d215881172f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1459,7 +1459,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, | |||
1459 | struct page **pagep, void **fsdata) | 1459 | struct page **pagep, void **fsdata) |
1460 | { | 1460 | { |
1461 | struct inode *inode = mapping->host; | 1461 | struct inode *inode = mapping->host; |
1462 | int ret, needed_blocks = ext4_writepage_trans_blocks(inode); | 1462 | int ret, needed_blocks; |
1463 | handle_t *handle; | 1463 | handle_t *handle; |
1464 | int retries = 0; | 1464 | int retries = 0; |
1465 | struct page *page; | 1465 | struct page *page; |
@@ -1470,6 +1470,11 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, | |||
1470 | "dev %s ino %lu pos %llu len %u flags %u", | 1470 | "dev %s ino %lu pos %llu len %u flags %u", |
1471 | inode->i_sb->s_id, inode->i_ino, | 1471 | inode->i_sb->s_id, inode->i_ino, |
1472 | (unsigned long long) pos, len, flags); | 1472 | (unsigned long long) pos, len, flags); |
1473 | /* | ||
1474 | * Reserve one block more for addition to orphan list in case | ||
1475 | * we allocate blocks but write fails for some reason | ||
1476 | */ | ||
1477 | needed_blocks = ext4_writepage_trans_blocks(inode) + 1; | ||
1473 | index = pos >> PAGE_CACHE_SHIFT; | 1478 | index = pos >> PAGE_CACHE_SHIFT; |
1474 | from = pos & (PAGE_CACHE_SIZE - 1); | 1479 | from = pos & (PAGE_CACHE_SIZE - 1); |
1475 | to = from + len; | 1480 | to = from + len; |
@@ -1503,15 +1508,30 @@ retry: | |||
1503 | 1508 | ||
1504 | if (ret) { | 1509 | if (ret) { |
1505 | unlock_page(page); | 1510 | unlock_page(page); |
1506 | ext4_journal_stop(handle); | ||
1507 | page_cache_release(page); | 1511 | page_cache_release(page); |
1508 | /* | 1512 | /* |
1509 | * block_write_begin may have instantiated a few blocks | 1513 | * block_write_begin may have instantiated a few blocks |
1510 | * outside i_size. Trim these off again. Don't need | 1514 | * outside i_size. Trim these off again. Don't need |
1511 | * i_size_read because we hold i_mutex. | 1515 | * i_size_read because we hold i_mutex. |
1516 | * | ||
1517 | * Add inode to orphan list in case we crash before | ||
1518 | * truncate finishes | ||
1512 | */ | 1519 | */ |
1513 | if (pos + len > inode->i_size) | 1520 | if (pos + len > inode->i_size) |
1521 | ext4_orphan_add(handle, inode); | ||
1522 | |||
1523 | ext4_journal_stop(handle); | ||
1524 | if (pos + len > inode->i_size) { | ||
1514 | vmtruncate(inode, inode->i_size); | 1525 | vmtruncate(inode, inode->i_size); |
1526 | /* | ||
1527 | * If vmtruncate failed early the inode might | ||
1528 | * still be on the orphan list; we need to | ||
1529 | * make sure the inode is removed from the | ||
1530 | * orphan list in that case. | ||
1531 | */ | ||
1532 | if (inode->i_nlink) | ||
1533 | ext4_orphan_del(NULL, inode); | ||
1534 | } | ||
1515 | } | 1535 | } |
1516 | 1536 | ||
1517 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 1537 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |