diff options
Diffstat (limited to 'fs/ext4/fsync.c')
| -rw-r--r-- | fs/ext4/fsync.c | 26 | 
1 files changed, 21 insertions, 5 deletions
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index da3bed3e0c2..036f78f7a1e 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -129,15 +129,30 @@ static int ext4_sync_parent(struct inode *inode)  {  	struct writeback_control wbc;  	struct dentry *dentry = NULL; +	struct inode *next;  	int ret = 0; -	while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { +	if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) +		return 0; +	inode = igrab(inode); +	while (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) +		dentry = NULL; +		spin_lock(&inode->i_lock); +		if (!list_empty(&inode->i_dentry)) { +			dentry = list_first_entry(&inode->i_dentry, +						  struct dentry, d_alias); +			dget(dentry); +		} +		spin_unlock(&inode->i_lock); +		if (!dentry)  			break; -		inode = dentry->d_parent->d_inode; +		next = igrab(dentry->d_parent->d_inode); +		dput(dentry); +		if (!next) +			break; +		iput(inode); +		inode = next;  		ret = sync_mapping_buffers(inode->i_mapping);  		if (ret)  			break; @@ -148,6 +163,7 @@ static int ext4_sync_parent(struct inode *inode)  		if (ret)  			break;  	} +	iput(inode);  	return ret;  }  |