Signed-off-by: Erez Zadok <[EMAIL PROTECTED]>
Acked-by: Herton Ronaldo Krzesinski <[EMAIL PROTECTED]>
---
 fs/unionfs/union.h |   39 +++++++++++++++++++++++++++++++++------
 1 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 6333488..0476f97 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -142,11 +142,18 @@ 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.
         */
        struct rw_semaphore rwsem;
+       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;
 };
@@ -234,10 +241,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)
-- 
1.5.2.2

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to