Re: [PATCH v3] writeback: Fix inode->i_io_list not be protected by inode->i_lock error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed 04-05-22 11:25:14, Jchao Sun wrote:
> Commit b35250c0816c ("writeback: Protect inode->i_io_list with
> inode->i_lock") made inode->i_io_list not only protected by
> wb->list_lock but also inode->i_lock, but inode_io_list_move_locked()
> was missed. Add lock there and also update comment describing things
> protected by inode->i_lock.
> 
> Fixes: b35250c0816c ("writeback: Protect inode->i_io_list with inode->i_lock")
> Signed-off-by: Jchao Sun <sunjunchao2870@xxxxxxxxx>

Almost there :). A few comments below:

> @@ -2402,6 +2404,9 @@ void __mark_inode_dirty(struct inode *inode, int flags)
>  			inode->i_state &= ~I_DIRTY_TIME;
>  		inode->i_state |= flags;
>  
> +		wb = locked_inode_to_wb_and_lock_list(inode);
> +		spin_lock(&inode->i_lock);
> +

We don't want to lock wb->list_lock if the inode was already dirty (which
is a common path). So you want something like:

		if (was_dirty)
			wb = locked_inode_to_wb_and_lock_list(inode);

(and initialize wb to NULL to make sure it does not contain stale value).

> @@ -2409,7 +2414,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
>  		 * list, based upon its state.
>  		 */
>  		if (inode->i_state & I_SYNC_QUEUED)
> -			goto out_unlock_inode;
> +			goto out_unlock;
>  
>  		/*
>  		 * Only add valid (hashed) inodes to the superblock's
> @@ -2417,22 +2422,19 @@ void __mark_inode_dirty(struct inode *inode, int flags)
>  		 */
>  		if (!S_ISBLK(inode->i_mode)) {
>  			if (inode_unhashed(inode))
> -				goto out_unlock_inode;
> +				goto out_unlock;
>  		}
>  		if (inode->i_state & I_FREEING)
> -			goto out_unlock_inode;
> +			goto out_unlock;
>  
>  		/*
>  		 * If the inode was already on b_dirty/b_io/b_more_io, don't
>  		 * reposition it (that would break b_dirty time-ordering).
>  		 */
>  		if (!was_dirty) {
> -			struct bdi_writeback *wb;
>  			struct list_head *dirty_list;
>  			bool wakeup_bdi = false;
>  
> -			wb = locked_inode_to_wb_and_lock_list(inode);
> -
>  			inode->dirtied_when = jiffies;
>  			if (dirtytime)
>  				inode->dirtied_time_when = jiffies;
> @@ -2446,6 +2448,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
>  							       dirty_list);
>  
>  			spin_unlock(&wb->list_lock);
> +			spin_unlock(&inode->i_lock);
>  			trace_writeback_dirty_inode_enqueue(inode);
>  
>  			/*
> @@ -2460,6 +2463,8 @@ void __mark_inode_dirty(struct inode *inode, int flags)
>  			return;
>  		}
>  	}
> +out_unlock:
> +	spin_unlock(&wb->list_lock);

wb->list lock will not be locked in some cases here. So you have to be more
careful about when you need to unlock it. Probably something like:

	if (wb)
		spin_unlock(&wb->list_lock);

and you can put this at the end inside the block "if ((inode->i_state &
flags) != flags)".

Also I'd note it is good to test your changes (it would likely uncover the
locking problem). For these filesystem related things xfstests are useful:

https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/

								Honza
-- 
Jan Kara <jack@xxxxxxxx>
SUSE Labs, CR



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux