diff options
author | David Chinner <david@fromorbit.com> | 2008-10-30 02:55:27 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 02:55:27 -0400 |
commit | 56e73ec47d749047f441e6b9d60d964535d31c3b (patch) | |
tree | 73423b4b01d760f95c5dcf1cff38ba4b56f6c969 /fs/xfs/xfs_iget.c | |
parent | 2b7035fd7473c799ca3372092d72c768c7db329d (diff) |
[XFS] Can't lock inodes in radix tree preload region
When we are inside a radix tree preload region, we cannot sleep. Recently
we moved the inode locking inside the preload region for the inode radix
tree. Fix that, and fix a missed unlock in another error path in the same
code at the same time.
SGI-PV: 987246
SGI-Modid: xfs-linux-melb:xfs-kern:32385a
Signed-off-by: David Chinner <david@fromorbit.com>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r-- | fs/xfs/xfs_iget.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index a1f209b0596f..377c0cd14999 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -159,18 +159,19 @@ xfs_iget_cache_miss( | |||
159 | goto out_destroy; | 159 | goto out_destroy; |
160 | } | 160 | } |
161 | 161 | ||
162 | if (lock_flags) | ||
163 | xfs_ilock(ip, lock_flags); | ||
164 | |||
162 | /* | 165 | /* |
163 | * Preload the radix tree so we can insert safely under the | 166 | * Preload the radix tree so we can insert safely under the |
164 | * write spinlock. | 167 | * write spinlock. Note that we cannot sleep inside the preload |
168 | * region. | ||
165 | */ | 169 | */ |
166 | if (radix_tree_preload(GFP_KERNEL)) { | 170 | if (radix_tree_preload(GFP_KERNEL)) { |
167 | error = EAGAIN; | 171 | error = EAGAIN; |
168 | goto out_destroy; | 172 | goto out_unlock; |
169 | } | 173 | } |
170 | 174 | ||
171 | if (lock_flags) | ||
172 | xfs_ilock(ip, lock_flags); | ||
173 | |||
174 | mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); | 175 | mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); |
175 | first_index = agino & mask; | 176 | first_index = agino & mask; |
176 | write_lock(&pag->pag_ici_lock); | 177 | write_lock(&pag->pag_ici_lock); |
@@ -181,7 +182,7 @@ xfs_iget_cache_miss( | |||
181 | WARN_ON(error != -EEXIST); | 182 | WARN_ON(error != -EEXIST); |
182 | XFS_STATS_INC(xs_ig_dup); | 183 | XFS_STATS_INC(xs_ig_dup); |
183 | error = EAGAIN; | 184 | error = EAGAIN; |
184 | goto out_unlock; | 185 | goto out_preload_end; |
185 | } | 186 | } |
186 | 187 | ||
187 | /* These values _must_ be set before releasing the radix tree lock! */ | 188 | /* These values _must_ be set before releasing the radix tree lock! */ |
@@ -193,9 +194,12 @@ xfs_iget_cache_miss( | |||
193 | *ipp = ip; | 194 | *ipp = ip; |
194 | return 0; | 195 | return 0; |
195 | 196 | ||
196 | out_unlock: | 197 | out_preload_end: |
197 | write_unlock(&pag->pag_ici_lock); | 198 | write_unlock(&pag->pag_ici_lock); |
198 | radix_tree_preload_end(); | 199 | radix_tree_preload_end(); |
200 | out_unlock: | ||
201 | if (lock_flags) | ||
202 | xfs_iunlock(ip, lock_flags); | ||
199 | out_destroy: | 203 | out_destroy: |
200 | xfs_idestroy(ip); | 204 | xfs_idestroy(ip); |
201 | return error; | 205 | return error; |