From 30fdb7bb524743eb9a4b2c5a7d1f6a5f579152e8 Mon Sep 17 00:00:00 2001 From: Frank Mayhar Date: Mon, 17 May 2010 08:00:00 -0400 Subject: [PATCH] --- yaml --- r: 198975 b: refs/heads/master c: 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c h: refs/heads/master i: 198973: 75d1447a389712ab770b6e0264f1540c55bf33d0 198971: d4ec2d170300d9b06b50e4afd218674c04d5bacb 198967: 4f9e83cc936e9b925507bdc013aa6de8faca74a2 198959: aecdce0efaa8a4648f0dab0f5720e3222918404b 198943: 3d010c5832390138a59aa1422661dc55616e1d31 198911: fb2ced2b16091fa622564d81416a1574e10e40a9 v: v3 --- [refs] | 2 +- trunk/fs/ext4/ext4.h | 1 + trunk/fs/ext4/fsync.c | 31 +++++++++++++++++++++++++++++-- trunk/fs/ext4/namei.c | 2 ++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index 69815c3384b0..5047b0130fdd 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 60e6679e28518ccd67169c4a539d8cc7490eb8a6 +refs/heads/master: 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c diff --git a/trunk/fs/ext4/ext4.h b/trunk/fs/ext4/ext4.h index 124ef771a618..60bd31026e7c 100644 --- a/trunk/fs/ext4/ext4.h +++ b/trunk/fs/ext4/ext4.h @@ -1180,6 +1180,7 @@ enum { EXT4_STATE_DA_ALLOC_CLOSE, /* Alloc DA blks on close */ EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */ EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/ + EXT4_STATE_NEWENTRY, /* File just added to dir */ }; #define EXT4_INODE_BIT_FNS(name, field) \ diff --git a/trunk/fs/ext4/fsync.c b/trunk/fs/ext4/fsync.c index 6ca7b6e59d83..e187f87acec0 100644 --- a/trunk/fs/ext4/fsync.c +++ b/trunk/fs/ext4/fsync.c @@ -34,6 +34,29 @@ #include +/* + * If we're not journaling and this is a just-created file, we have to + * sync our parent directory (if it was freshly created) since + * otherwise it will only be written by writeback, leaving a huge + * window during which a crash may lose the file. This may apply for + * the parent directory's parent as well, and so on recursively, if + * they are also freshly created. + */ +static void ext4_sync_parent(struct inode *inode) +{ + struct dentry *dentry = NULL; + + while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { + ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); + dentry = list_entry(inode->i_dentry.next, + struct dentry, d_alias); + if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) + break; + inode = dentry->d_parent->d_inode; + sync_mapping_buffers(inode->i_mapping); + } +} + /* * akpm: A new design for ext4_sync_file(). * @@ -67,8 +90,12 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) if (ret < 0) return ret; - if (!journal) - return simple_fsync(file, dentry, datasync); + if (!journal) { + ret = simple_fsync(file, dentry, datasync); + if (!ret && !list_empty(&inode->i_dentry)) + ext4_sync_parent(inode); + return ret; + } /* * data=writeback,ordered: diff --git a/trunk/fs/ext4/namei.c b/trunk/fs/ext4/namei.c index 83be743c8d1f..a43e6617b351 100644 --- a/trunk/fs/ext4/namei.c +++ b/trunk/fs/ext4/namei.c @@ -1517,6 +1517,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); retval = add_dirent_to_buf(handle, dentry, inode, de, bh); brelse(bh); + if (retval == 0) + ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY); return retval; }