From patchwork Wed Apr 6 21:01:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Theodore Ts'o X-Patchwork-Id: 90072 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 6A10CB6F71 for ; Thu, 7 Apr 2011 07:01:43 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751232Ab1DFVBl (ORCPT ); Wed, 6 Apr 2011 17:01:41 -0400 Received: from li9-11.members.linode.com ([67.18.176.11]:48561 "EHLO test.thunk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751075Ab1DFVBl (ORCPT ); Wed, 6 Apr 2011 17:01:41 -0400 Received: from root (helo=tytso-glaptop) by test.thunk.org with local-esmtp (Exim 4.69) (envelope-from ) id 1Q7Zqx-0002Sh-K6; Wed, 06 Apr 2011 21:01:27 +0000 Received: from tytso by tytso-glaptop with local (Exim 4.71) (envelope-from ) id 1Q7Zqw-0004cl-J9; Wed, 06 Apr 2011 17:01:26 -0400 Date: Wed, 6 Apr 2011 17:01:26 -0400 From: Ted Ts'o To: Curt Wohlgemuth Cc: linux-ext4@vger.kernel.org Subject: Re: [PATCH] ext4: sync the directory inode in ext4_sync_parent() Message-ID: <20110406210126.GO2832@thunk.org> References: <1302045844-23678-1-git-send-email-curtw@google.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1302045844-23678-1-git-send-email-curtw@google.com> User-Agent: Mutt/1.5.20 (2009-06-14) X-SA-Exim-Connect-IP: X-SA-Exim-Mail-From: tytso@thunk.org X-SA-Exim-Scanned: No (on test.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 Hi Curt, Thanks, accepted into the tree. I made a few tiny stylistic changes (mainly by replacing "goto out" with "break"). - Ted From 8429a2e121372395f25d80a486ef065e77139ebb Mon Sep 17 00:00:00 2001 From: Curt Wohlgemuth Date: Wed, 6 Apr 2011 16:57:09 -0400 Subject: [PATCH] ext4: sync the directory inode in ext4_sync_parent() ext4 has taken the stance that, in the absence of a journal, when an fsync/fdatasync of an inode is done, the parent directory should be sync'ed if this inode entry is new. ext4_sync_parent(), which implements this, does indeed sync the dirent pages for parent directories, but it does not sync the directory *inode*. This patch fixes this. Also now return error status from ext4_sync_parent(). I tested this using a power fail test, which panics a machine running a file server getting requests from a client. Without this patch, on about every other test run, the server is missing many, many files that had been synced. With this patch, on > 6 runs, I see zero files being lost. Signed-off-by: Curt Wohlgemuth Signed-off-by: "Theodore Ts'o" --- fs/ext4/fsync.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 7f74019..b1f9b5f 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -125,9 +125,11 @@ extern int ext4_flush_completed_IO(struct inode *inode) * 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) +static int ext4_sync_parent(struct inode *inode) { + struct writeback_control wbc; struct dentry *dentry = NULL; + int ret = 0; while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); @@ -136,8 +138,17 @@ static void ext4_sync_parent(struct inode *inode) if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) break; inode = dentry->d_parent->d_inode; - sync_mapping_buffers(inode->i_mapping); + ret = sync_mapping_buffers(inode->i_mapping); + if (ret) + break; + memset(&wbc, 0, sizeof(wbc)); + wbc.sync_mode = WB_SYNC_ALL; + wbc.nr_to_write = 0; /* only write out the inode */ + ret = sync_inode(inode, &wbc); + if (ret) + break; } + return ret; } /* @@ -176,7 +187,7 @@ int ext4_sync_file(struct file *file, int datasync) if (!journal) { ret = generic_file_fsync(file, datasync); if (!ret && !list_empty(&inode->i_dentry)) - ext4_sync_parent(inode); + ret = ext4_sync_parent(inode); goto out; }