mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
ext3: make sure inode is deleted from orphan list after truncate
As Ted pointed out, it can happen that ext3_truncate() returns without removing inode from orphan list. This way we could in some rare cases (like when we get ENOMEM from an allocation in ext3_truncate called because of failed ext3_write_begin) leave the inode on orphan list and that triggers assertion failure on umount. So make ext3_truncate() always remove inode from in-memory orphan list. Cc: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
6f3f1cb21f
commit
ef43618a47
1 changed files with 11 additions and 9 deletions
|
@ -2374,7 +2374,7 @@ void ext3_truncate(struct inode *inode)
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
if (!ext3_can_truncate(inode))
|
if (!ext3_can_truncate(inode))
|
||||||
return;
|
goto out_notrans;
|
||||||
|
|
||||||
if (inode->i_size == 0 && ext3_should_writeback_data(inode))
|
if (inode->i_size == 0 && ext3_should_writeback_data(inode))
|
||||||
ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE;
|
ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE;
|
||||||
|
@ -2390,7 +2390,7 @@ void ext3_truncate(struct inode *inode)
|
||||||
page = grab_cache_page(mapping,
|
page = grab_cache_page(mapping,
|
||||||
inode->i_size >> PAGE_CACHE_SHIFT);
|
inode->i_size >> PAGE_CACHE_SHIFT);
|
||||||
if (!page)
|
if (!page)
|
||||||
return;
|
goto out_notrans;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = start_transaction(inode);
|
handle = start_transaction(inode);
|
||||||
|
@ -2401,7 +2401,7 @@ void ext3_truncate(struct inode *inode)
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
}
|
}
|
||||||
return; /* AKPM: return what? */
|
goto out_notrans;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_block = (inode->i_size + blocksize-1)
|
last_block = (inode->i_size + blocksize-1)
|
||||||
|
@ -2525,6 +2525,14 @@ out_stop:
|
||||||
ext3_orphan_del(handle, inode);
|
ext3_orphan_del(handle, inode);
|
||||||
|
|
||||||
ext3_journal_stop(handle);
|
ext3_journal_stop(handle);
|
||||||
|
return;
|
||||||
|
out_notrans:
|
||||||
|
/*
|
||||||
|
* Delete the inode from orphan list so that it doesn't stay there
|
||||||
|
* forever and trigger assertion on umount.
|
||||||
|
*/
|
||||||
|
if (inode->i_nlink)
|
||||||
|
ext3_orphan_del(NULL, inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
|
static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
|
||||||
|
@ -3122,12 +3130,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
|
|
||||||
rc = inode_setattr(inode, attr);
|
rc = inode_setattr(inode, attr);
|
||||||
|
|
||||||
/* If inode_setattr's call to ext3_truncate failed to get a
|
|
||||||
* transaction handle at all, we need to clean up the in-core
|
|
||||||
* orphan list manually. */
|
|
||||||
if (inode->i_nlink)
|
|
||||||
ext3_orphan_del(NULL, inode);
|
|
||||||
|
|
||||||
if (!rc && (ia_valid & ATTR_MODE))
|
if (!rc && (ia_valid & ATTR_MODE))
|
||||||
rc = ext3_acl_chmod(inode);
|
rc = ext3_acl_chmod(inode);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue