diff options
author | Cecil Hugh Watson <knoppmyth@gmail.com> | 2009-08-17 06:31:43 (GMT) |
---|---|---|
committer | Cecil Hugh Watson <knoppmyth@gmail.com> | 2009-08-17 06:31:43 (GMT) |
commit | 6361f26251ab679de77f9db79b16632df05a8235 (patch) | |
tree | 7e54548ca41245bf413cfd3c6db47d1d448b3968 /abs/core-testing/kernel26/ext4.patch | |
parent | 3df8e145831128ee1de658a48057cd2afefea94f (diff) | |
download | linhes_pkgbuild-6361f26251ab679de77f9db79b16632df05a8235.zip linhes_pkgbuild-6361f26251ab679de77f9db79b16632df05a8235.tar.gz linhes_pkgbuild-6361f26251ab679de77f9db79b16632df05a8235.tar.bz2 |
Kernel26:Patch for EXT4 data loss.
Diffstat (limited to 'abs/core-testing/kernel26/ext4.patch')
-rw-r--r-- | abs/core-testing/kernel26/ext4.patch | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/abs/core-testing/kernel26/ext4.patch b/abs/core-testing/kernel26/ext4.patch new file mode 100644 index 0000000..40ecfde --- /dev/null +++ b/abs/core-testing/kernel26/ext4.patch @@ -0,0 +1,152 @@ +diff -ruaN linux-2.6.28.orig/fs/ext4/ext4.h linux-2.6.28/fs/ext4/ext4.h +--- linux-2.6.28.orig/fs/ext4/ext4.h 2008-12-24 23:26:37.000000000 +0000 ++++ linux-2.6.28/fs/ext4/ext4.h 2009-08-17 04:22:43.000000000 +0000 +@@ -254,6 +254,7 @@ + #define EXT4_STATE_NEW 0x00000002 /* inode is newly created */ + #define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ + #define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */ ++#define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */ + + /* Used to pass group descriptor data when online resize is done */ + struct ext4_new_group_input { +@@ -301,7 +302,9 @@ + #define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) + #define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) + #define EXT4_IOC_MIGRATE _IO('f', 9) ++ /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ + /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ ++#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) + + /* + * ioctl commands in 32 bit emulation +@@ -1088,6 +1091,7 @@ + extern void ext4_truncate(struct inode *); + extern void ext4_set_inode_flags(struct inode *); + extern void ext4_get_inode_flags(struct ext4_inode_info *); ++extern int ext4_alloc_da_blocks(struct inode *inode); + extern void ext4_set_aops(struct inode *inode); + extern int ext4_writepage_trans_blocks(struct inode *); + extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); +diff -ruaN linux-2.6.28.orig/fs/ext4/file.c linux-2.6.28/fs/ext4/file.c +--- linux-2.6.28.orig/fs/ext4/file.c 2008-12-24 23:26:37.000000000 +0000 ++++ linux-2.6.28/fs/ext4/file.c 2009-08-17 04:15:17.000000000 +0000 +@@ -33,6 +33,10 @@ + */ + static int ext4_release_file(struct inode *inode, struct file *filp) + { ++ if (EXT4_I(inode)->i_state & EXT4_STATE_DA_ALLOC_CLOSE) { ++ ext4_alloc_da_blocks(inode); ++ EXT4_I(inode)->i_state &= ~EXT4_STATE_DA_ALLOC_CLOSE; ++ } + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && + (atomic_read(&inode->i_writecount) == 1)) +diff -ruaN linux-2.6.28.orig/fs/ext4/inode.c linux-2.6.28/fs/ext4/inode.c +--- linux-2.6.28.orig/fs/ext4/inode.c 2008-12-24 23:26:37.000000000 +0000 ++++ linux-2.6.28/fs/ext4/inode.c 2009-08-17 04:34:48.000000000 +0000 +@@ -2686,6 +2686,42 @@ + return; + } + ++/* ++ * Force all delayed allocation blocks to be allocated for a given inode. ++ */ ++int ext4_alloc_da_blocks(struct inode *inode) ++{ ++ if (!EXT4_I(inode)->i_reserved_data_blocks && ++ !EXT4_I(inode)->i_reserved_meta_blocks) ++ return 0; ++ /* ++ * We do something simple for now. The filemap_flush() will ++ * also start triggering a write of the data blocks, which is ++ * not strictly speaking necessary (and for users of ++ * laptop_mode, not even desirable). However, to do otherwise ++ * would require replicating code paths in: ++ * ++ * ext4_da_writepages() -> ++ * write_cache_pages() ---> (via passed in callback function) ++ * __mpage_da_writepage() --> ++ * mpage_ad_bh_to_extent() ++ * mpage_da_map_blocks() ++ * ++ * The problem is that write_cache_pages(), and then redirty all of ++ * the pages calling redirty_page_for_writeback() but that ++ * would be ugly in the extreme. So instead we would need to ++ * replicate parts of the code in teh above functions, ++ * simplifying them because we wouldn't actually intend to ++ * write out the pages, but rather only collect contiguous ++ * logical block extents, call the multi-block allocator, and ++ * then update the buffer heads with the block allocations. ++ * ++ * For now, though we'll cheat by calling filemap_flush(), ++ * which will map the blocks, and start the I/O, but not ++ * actually wait for the I/O to complte. ++ */ ++ return filemap_flush(inode->i_mapping); ++} + + /* + * bmap() is special. It gets used by applications such as lilo and by +@@ -3695,6 +3731,9 @@ + if (!ext4_can_truncate(inode)) + return; + ++ if (inode->i_size == 0) ++ ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE; ++ + if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { + ext4_ext_truncate(inode); + return; +diff -ruaN linux-2.6.28.orig/fs/ext4/ioctl.c linux-2.6.28/fs/ext4/ioctl.c +--- linux-2.6.28.orig/fs/ext4/ioctl.c 2008-12-24 23:26:37.000000000 +0000 ++++ linux-2.6.28/fs/ext4/ioctl.c 2009-08-17 04:38:43.000000000 +0000 +@@ -263,6 +263,20 @@ + return err; + } + ++ case EXT4_IOC_ALLOC_DA_BLKS: ++ { ++ int err; ++ if (!is_owner_or_cap(inode)) ++ return -EACCES; ++ ++ err = mnt_want_write(filp->f_path.mnt); ++ if (err) ++ return err; ++ err = ext4_alloc_da_blocks(inode); ++ mnt_drop_write(filp->f_path.mnt); ++ return err; ++ } ++ + default: + return -ENOTTY; + } +diff -ruaN linux-2.6.28.orig/fs/ext4/namei.c linux-2.6.28/fs/ext4/namei.c +--- linux-2.6.28.orig/fs/ext4/namei.c 2008-12-24 23:26:37.000000000 +0000 ++++ linux-2.6.28/fs/ext4/namei.c 2009-08-17 04:11:01.000000000 +0000 +@@ -2283,7 +2283,7 @@ + struct inode *old_inode, *new_inode; + struct buffer_head *old_bh, *new_bh, *dir_bh; + struct ext4_dir_entry_2 *old_de, *new_de; +- int retval; ++ int retval, force_da_alloc = 0; + + old_bh = new_bh = dir_bh = NULL; + +@@ -2421,6 +2421,7 @@ + ext4_mark_inode_dirty(handle, new_inode); + if (!new_inode->i_nlink) + ext4_orphan_add(handle, new_inode); ++ force_da_alloc = 1; + } + retval = 0; + +@@ -2429,6 +2430,8 @@ + brelse(old_bh); + brelse(new_bh); + ext4_journal_stop(handle); ++ if (retval == 0 && force_da_alloc) ++ ext4_alloc_da_blocks(old_inode); + return retval; + } + |