[Unionfs] Locking issue with unionfs

Herton Ronaldo Krzesinski herton at mandriva.com.br
Thu Nov 1 11:38:54 EDT 2007


Em Wednesday 31 October 2007 22:27:18 Erez Zadok escreveu:
> Oliver/Herton,
>
> Here's a patch that cleanly solves this self-deadlock issue.  You should
> apply it on a clean unionfs-2.1.7 (and *remove* the write_unlock/re-lock
> around the do_remount_*_option calls which you've added).  With this patch,
> you won't get into a deadlock if you change the branch configuration of a
> pivot_rooted union, and at the same time you won't open yourself to a
> concurrency risk between normal branch-management commands and in-flight
> file operations.
>
> I'd appreciate if you can test this patch and report back.

Thanks, works fine now, no more deadlocks. If you want you can add:
Tested by: Herton Ronaldo Krzesinski <herton at mandriva.com>

>
> Cheers,
> Erez.
>
>
> diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
> index 659d6cc..b1fef7d 100644
> --- a/fs/unionfs/union.h
> +++ b/fs/unionfs/union.h
> @@ -142,15 +142,22 @@ struct unionfs_sb_info {
>  	 * This rwsem is used to make sure that a branch management
>  	 * operation...
>  	 *   1) will not begin before all currently in-flight operations
> -	 *      complete
> +	 *      complete.
>  	 *   2) any new operations do not execute until the currently
> -	 *      running branch management operation completes
> +	 *      running branch management operation completes.
> +	 *
> +	 * The write_lock_owner records the PID of the task which grabbed
> +	 * the rw_sem for writing.  If the same task also tries to grab the
> +	 * read lock, we allow it.  This prevents a self-deadlock when
> +	 * branch-management is used on a pivot_root'ed union, because we
> +	 * have to ->lookup paths which belong to the same union.
>  	 */
>  #ifdef CONFIG_PREEMPT_RT
>  	struct compat_rw_semaphore rwsem;
>  #else /* not CONFIG_PREEMPT_RT */
>  	struct rw_semaphore rwsem;
>  #endif /* not CONFIG_PREEMPT_RT */
> +	pid_t write_lock_owner;	/* PID of rw_sem owner (write lock) */
>  	int high_branch_id;	/* last unique branch ID given */
>  	struct unionfs_data *data;
>  };
> @@ -238,10 +245,30 @@ static inline off_t rdstate2offset(struct
> unionfs_dir_state *buf) return tmp;
>  }
>
> -#define unionfs_read_lock(sb)	 down_read(&UNIONFS_SB(sb)->rwsem)
> -#define unionfs_read_unlock(sb)	 up_read(&UNIONFS_SB(sb)->rwsem)
> -#define unionfs_write_lock(sb)	 down_write(&UNIONFS_SB(sb)->rwsem)
> -#define unionfs_write_unlock(sb) up_write(&UNIONFS_SB(sb)->rwsem)
> +static inline void unionfs_read_lock(struct super_block *sb)
> +{
> +	if (UNIONFS_SB(sb)->write_lock_owner &&
> +	    UNIONFS_SB(sb)->write_lock_owner == current->pid)
> +		return;
> +	down_read(&UNIONFS_SB(sb)->rwsem);
> +}
> +static inline void unionfs_read_unlock(struct super_block *sb)
> +{
> +	if (UNIONFS_SB(sb)->write_lock_owner &&
> +	    UNIONFS_SB(sb)->write_lock_owner == current->pid)
> +		return;
> +	up_read(&UNIONFS_SB(sb)->rwsem);
> +}
> +static inline void unionfs_write_lock(struct super_block *sb)
> +{
> +	down_write(&UNIONFS_SB(sb)->rwsem);
> +	UNIONFS_SB(sb)->write_lock_owner = current->pid;
> +}
> +static inline void unionfs_write_unlock(struct super_block *sb)
> +{
> +	up_write(&UNIONFS_SB(sb)->rwsem);
> +	UNIONFS_SB(sb)->write_lock_owner = 0;
> +}
>
>  static inline void unionfs_double_lock_dentry(struct dentry *d1,
>  					      struct dentry *d2)

--
[]'s
Herton


More information about the unionfs mailing list