From patchwork Fri Jun 21 19:30:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Theodore Ts'o X-Patchwork-Id: 253307 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 58D5E2C0399 for ; Sat, 22 Jun 2013 05:30:36 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1423740Ab3FUTaf (ORCPT ); Fri, 21 Jun 2013 15:30:35 -0400 Received: from li9-11.members.linode.com ([67.18.176.11]:60142 "EHLO imap.thunk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1423672Ab3FUTae (ORCPT ); Fri, 21 Jun 2013 15:30:34 -0400 Received: from root (helo=closure.thunk.org) by imap.thunk.org with local-esmtp (Exim 4.80) (envelope-from ) id 1Uq77I-00028Q-Lg; Fri, 21 Jun 2013 19:35:28 +0000 Received: by closure.thunk.org (Postfix, from userid 15806) id 9C10D5801B9; Fri, 21 Jun 2013 15:30:30 -0400 (EDT) From: Theodore Ts'o To: Ext4 Developers List Cc: desrt@desrt.ca, Theodore Ts'o Subject: [PATCH 2/2] ext4: allocate delayed allocation blocks before rename Date: Fri, 21 Jun 2013 15:30:30 -0400 Message-Id: <1371843030-24038-2-git-send-email-tytso@mit.edu> X-Mailer: git-send-email 1.7.12.rc0.22.gcdd159b In-Reply-To: <1371843030-24038-1-git-send-email-tytso@mit.edu> References: <1371843030-24038-1-git-send-email-tytso@mit.edu> X-SA-Exim-Connect-IP: X-SA-Exim-Mail-From: tytso@thunk.org X-SA-Exim-Scanned: No (on imap.thunk.org); SAEximRunCond expanded to false Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org When ext4_rename() overwrites an already existing file, call ext4_alloc_da_blocks() before starting the journal handle which actually does the rename, instead of doing this afterwards. This improves the likelihood that the contents will survive a crash if an application replaces a file using the sequence: 1) write replacement contents to foo.new 2) 3) rename foo.new to foo It is still not a guarantee, since ext4_alloc_da_blocks() is *not* doing a file integrity sync; this means if foo.new is a very large file, it may not be completely flushed out to disk. However, for files smaller than a megabyte or so, any dirty pages should be flushed out before we do the rename operation, and so at the next journal commit, the CACHE FLUSH command will make sure al of these pages are safely on the disk platter. Signed-off-by: "Theodore Ts'o" --- fs/ext4/namei.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f57980c..ca8174b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2961,6 +2961,10 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle, /* * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. + * + * n.b. old_{dentry,inode) refers to the source dentry/inode + * while new_{dentry,inode) refers to the destination dentry/inode + * This comes from rename(const char *oldpath, const char *newpath) */ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) @@ -2969,7 +2973,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, 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, force_da_alloc = 0; + int retval; int inlined = 0, new_inlined = 0; struct ext4_dir_entry_2 *parent_de; @@ -3004,6 +3008,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, new_bh = NULL; } } + if (new_inode && !test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC)) + ext4_alloc_da_blocks(old_inode); handle = ext4_journal_start(old_dir, EXT4_HT_DIR, (2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) + @@ -3144,8 +3150,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ext4_mark_inode_dirty(handle, new_inode); if (!new_inode->i_nlink) ext4_orphan_add(handle, new_inode); - if (!test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC)) - force_da_alloc = 1; } retval = 0; @@ -3155,8 +3159,6 @@ end_rename: brelse(new_bh); if (handle) ext4_journal_stop(handle); - if (retval == 0 && force_da_alloc) - ext4_alloc_da_blocks(old_inode); return retval; }