aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:39 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:23 -0500
commit58db63d086790eec2ed433f9d8c4962239809cf8 (patch)
treee8fa4238167f92bb0dbded4d2df1498d8c4e9404 /fs/dcache.c
parentb5c84bf6f6fa3a7dfdcb556023a62953574b60ee (diff)
fs: dcache avoid starvation in dcache multi-step operations
Long lived dcache "multi-step" operations which retry on rename seq can be starved with a lot of rename activity. If they fail after the 1st pass, take the rename_lock for writing to avoid further starvation. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 0dbae053b664..bf6294a20f0e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -973,10 +973,11 @@ int have_submounts(struct dentry *parent)
973 struct dentry *this_parent; 973 struct dentry *this_parent;
974 struct list_head *next; 974 struct list_head *next;
975 unsigned seq; 975 unsigned seq;
976 int locked = 0;
976 977
977rename_retry:
978 this_parent = parent;
979 seq = read_seqbegin(&rename_lock); 978 seq = read_seqbegin(&rename_lock);
979again:
980 this_parent = parent;
980 981
981 if (d_mountpoint(parent)) 982 if (d_mountpoint(parent))
982 goto positive; 983 goto positive;
@@ -1021,7 +1022,7 @@ resume:
1021 /* might go back up the wrong parent if we have had a rename 1022 /* might go back up the wrong parent if we have had a rename
1022 * or deletion */ 1023 * or deletion */
1023 if (this_parent != child->d_parent || 1024 if (this_parent != child->d_parent ||
1024 read_seqretry(&rename_lock, seq)) { 1025 (!locked && read_seqretry(&rename_lock, seq))) {
1025 spin_unlock(&this_parent->d_lock); 1026 spin_unlock(&this_parent->d_lock);
1026 rcu_read_unlock(); 1027 rcu_read_unlock();
1027 goto rename_retry; 1028 goto rename_retry;
@@ -1031,13 +1032,22 @@ resume:
1031 goto resume; 1032 goto resume;
1032 } 1033 }
1033 spin_unlock(&this_parent->d_lock); 1034 spin_unlock(&this_parent->d_lock);
1034 if (read_seqretry(&rename_lock, seq)) 1035 if (!locked && read_seqretry(&rename_lock, seq))
1035 goto rename_retry; 1036 goto rename_retry;
1037 if (locked)
1038 write_sequnlock(&rename_lock);
1036 return 0; /* No mount points found in tree */ 1039 return 0; /* No mount points found in tree */
1037positive: 1040positive:
1038 if (read_seqretry(&rename_lock, seq)) 1041 if (!locked && read_seqretry(&rename_lock, seq))
1039 goto rename_retry; 1042 goto rename_retry;
1043 if (locked)
1044 write_sequnlock(&rename_lock);
1040 return 1; 1045 return 1;
1046
1047rename_retry:
1048 locked = 1;
1049 write_seqlock(&rename_lock);
1050 goto again;
1041} 1051}
1042EXPORT_SYMBOL(have_submounts); 1052EXPORT_SYMBOL(have_submounts);
1043 1053
@@ -1061,11 +1071,11 @@ static int select_parent(struct dentry * parent)
1061 struct list_head *next; 1071 struct list_head *next;
1062 unsigned seq; 1072 unsigned seq;
1063 int found = 0; 1073 int found = 0;
1074 int locked = 0;
1064 1075
1065rename_retry:
1066 this_parent = parent;
1067 seq = read_seqbegin(&rename_lock); 1076 seq = read_seqbegin(&rename_lock);
1068 1077again:
1078 this_parent = parent;
1069 spin_lock(&this_parent->d_lock); 1079 spin_lock(&this_parent->d_lock);
1070repeat: 1080repeat:
1071 next = this_parent->d_subdirs.next; 1081 next = this_parent->d_subdirs.next;
@@ -1127,7 +1137,7 @@ resume:
1127 /* might go back up the wrong parent if we have had a rename 1137 /* might go back up the wrong parent if we have had a rename
1128 * or deletion */ 1138 * or deletion */
1129 if (this_parent != child->d_parent || 1139 if (this_parent != child->d_parent ||
1130 read_seqretry(&rename_lock, seq)) { 1140 (!locked && read_seqretry(&rename_lock, seq))) {
1131 spin_unlock(&this_parent->d_lock); 1141 spin_unlock(&this_parent->d_lock);
1132 rcu_read_unlock(); 1142 rcu_read_unlock();
1133 goto rename_retry; 1143 goto rename_retry;
@@ -1138,9 +1148,18 @@ resume:
1138 } 1148 }
1139out: 1149out:
1140 spin_unlock(&this_parent->d_lock); 1150 spin_unlock(&this_parent->d_lock);
1141 if (read_seqretry(&rename_lock, seq)) 1151 if (!locked && read_seqretry(&rename_lock, seq))
1142 goto rename_retry; 1152 goto rename_retry;
1153 if (locked)
1154 write_sequnlock(&rename_lock);
1143 return found; 1155 return found;
1156
1157rename_retry:
1158 if (found)
1159 return found;
1160 locked = 1;
1161 write_seqlock(&rename_lock);
1162 goto again;
1144} 1163}
1145 1164
1146/** 1165/**
@@ -2655,10 +2674,11 @@ void d_genocide(struct dentry *root)
2655 struct dentry *this_parent; 2674 struct dentry *this_parent;
2656 struct list_head *next; 2675 struct list_head *next;
2657 unsigned seq; 2676 unsigned seq;
2677 int locked = 0;
2658 2678
2659rename_retry:
2660 this_parent = root;
2661 seq = read_seqbegin(&rename_lock); 2679 seq = read_seqbegin(&rename_lock);
2680again:
2681 this_parent = root;
2662 spin_lock(&this_parent->d_lock); 2682 spin_lock(&this_parent->d_lock);
2663repeat: 2683repeat:
2664 next = this_parent->d_subdirs.next; 2684 next = this_parent->d_subdirs.next;
@@ -2703,7 +2723,7 @@ resume:
2703 /* might go back up the wrong parent if we have had a rename 2723 /* might go back up the wrong parent if we have had a rename
2704 * or deletion */ 2724 * or deletion */
2705 if (this_parent != child->d_parent || 2725 if (this_parent != child->d_parent ||
2706 read_seqretry(&rename_lock, seq)) { 2726 (!locked && read_seqretry(&rename_lock, seq))) {
2707 spin_unlock(&this_parent->d_lock); 2727 spin_unlock(&this_parent->d_lock);
2708 rcu_read_unlock(); 2728 rcu_read_unlock();
2709 goto rename_retry; 2729 goto rename_retry;
@@ -2713,8 +2733,16 @@ resume:
2713 goto resume; 2733 goto resume;
2714 } 2734 }
2715 spin_unlock(&this_parent->d_lock); 2735 spin_unlock(&this_parent->d_lock);
2716 if (read_seqretry(&rename_lock, seq)) 2736 if (!locked && read_seqretry(&rename_lock, seq))
2717 goto rename_retry; 2737 goto rename_retry;
2738 if (locked)
2739 write_sequnlock(&rename_lock);
2740 return;
2741
2742rename_retry:
2743 locked = 1;
2744 write_seqlock(&rename_lock);
2745 goto again;
2718} 2746}
2719 2747
2720/** 2748/**