From 994552b6b04f4506a1554cf4630c605afe1d3ca6 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Fri, 7 Jan 2011 17:49:39 +1100 Subject: [PATCH] --- yaml --- r: 226711 b: refs/heads/master c: 58db63d086790eec2ed433f9d8c4962239809cf8 h: refs/heads/master i: 226709: 279642b6b2b185cd1eedcc8f696bc2a3444f55f5 226707: 13b1e047455037398f90d9994cc8ed6f8c22485c 226703: 09cb8400a6b56910a16d85b4a057a227f4cdb728 v: v3 --- [refs] | 2 +- trunk/fs/dcache.c | 56 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/[refs] b/[refs] index a38008d672a5..6f38752f3e3f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b5c84bf6f6fa3a7dfdcb556023a62953574b60ee +refs/heads/master: 58db63d086790eec2ed433f9d8c4962239809cf8 diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index 0dbae053b664..bf6294a20f0e 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -973,10 +973,11 @@ int have_submounts(struct dentry *parent) struct dentry *this_parent; struct list_head *next; unsigned seq; + int locked = 0; -rename_retry: - this_parent = parent; seq = read_seqbegin(&rename_lock); +again: + this_parent = parent; if (d_mountpoint(parent)) goto positive; @@ -1021,7 +1022,7 @@ int have_submounts(struct dentry *parent) /* might go back up the wrong parent if we have had a rename * or deletion */ if (this_parent != child->d_parent || - read_seqretry(&rename_lock, seq)) { + (!locked && read_seqretry(&rename_lock, seq))) { spin_unlock(&this_parent->d_lock); rcu_read_unlock(); goto rename_retry; @@ -1031,13 +1032,22 @@ int have_submounts(struct dentry *parent) goto resume; } spin_unlock(&this_parent->d_lock); - if (read_seqretry(&rename_lock, seq)) + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + if (locked) + write_sequnlock(&rename_lock); return 0; /* No mount points found in tree */ positive: - if (read_seqretry(&rename_lock, seq)) + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + if (locked) + write_sequnlock(&rename_lock); return 1; + +rename_retry: + locked = 1; + write_seqlock(&rename_lock); + goto again; } EXPORT_SYMBOL(have_submounts); @@ -1061,11 +1071,11 @@ static int select_parent(struct dentry * parent) struct list_head *next; unsigned seq; int found = 0; + int locked = 0; -rename_retry: - this_parent = parent; seq = read_seqbegin(&rename_lock); - +again: + this_parent = parent; spin_lock(&this_parent->d_lock); repeat: next = this_parent->d_subdirs.next; @@ -1127,7 +1137,7 @@ static int select_parent(struct dentry * parent) /* might go back up the wrong parent if we have had a rename * or deletion */ if (this_parent != child->d_parent || - read_seqretry(&rename_lock, seq)) { + (!locked && read_seqretry(&rename_lock, seq))) { spin_unlock(&this_parent->d_lock); rcu_read_unlock(); goto rename_retry; @@ -1138,9 +1148,18 @@ static int select_parent(struct dentry * parent) } out: spin_unlock(&this_parent->d_lock); - if (read_seqretry(&rename_lock, seq)) + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + if (locked) + write_sequnlock(&rename_lock); return found; + +rename_retry: + if (found) + return found; + locked = 1; + write_seqlock(&rename_lock); + goto again; } /** @@ -2655,10 +2674,11 @@ void d_genocide(struct dentry *root) struct dentry *this_parent; struct list_head *next; unsigned seq; + int locked = 0; -rename_retry: - this_parent = root; seq = read_seqbegin(&rename_lock); +again: + this_parent = root; spin_lock(&this_parent->d_lock); repeat: next = this_parent->d_subdirs.next; @@ -2703,7 +2723,7 @@ void d_genocide(struct dentry *root) /* might go back up the wrong parent if we have had a rename * or deletion */ if (this_parent != child->d_parent || - read_seqretry(&rename_lock, seq)) { + (!locked && read_seqretry(&rename_lock, seq))) { spin_unlock(&this_parent->d_lock); rcu_read_unlock(); goto rename_retry; @@ -2713,8 +2733,16 @@ void d_genocide(struct dentry *root) goto resume; } spin_unlock(&this_parent->d_lock); - if (read_seqretry(&rename_lock, seq)) + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + if (locked) + write_sequnlock(&rename_lock); + return; + +rename_retry: + locked = 1; + write_seqlock(&rename_lock); + goto again; } /**