diff options
Diffstat (limited to 'fs/ocfs2/dlmglue.c')
| -rw-r--r-- | fs/ocfs2/dlmglue.c | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 19986959d149..6bd690b5a061 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
| @@ -3144,22 +3144,60 @@ out: | |||
| 3144 | return 0; | 3144 | return 0; |
| 3145 | } | 3145 | } |
| 3146 | 3146 | ||
| 3147 | static void ocfs2_process_blocked_lock(struct ocfs2_super *osb, | ||
| 3148 | struct ocfs2_lock_res *lockres); | ||
| 3149 | |||
| 3147 | /* Mark the lockres as being dropped. It will no longer be | 3150 | /* Mark the lockres as being dropped. It will no longer be |
| 3148 | * queued if blocking, but we still may have to wait on it | 3151 | * queued if blocking, but we still may have to wait on it |
| 3149 | * being dequeued from the downconvert thread before we can consider | 3152 | * being dequeued from the downconvert thread before we can consider |
| 3150 | * it safe to drop. | 3153 | * it safe to drop. |
| 3151 | * | 3154 | * |
| 3152 | * You can *not* attempt to call cluster_lock on this lockres anymore. */ | 3155 | * You can *not* attempt to call cluster_lock on this lockres anymore. */ |
| 3153 | void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres) | 3156 | void ocfs2_mark_lockres_freeing(struct ocfs2_super *osb, |
| 3157 | struct ocfs2_lock_res *lockres) | ||
| 3154 | { | 3158 | { |
| 3155 | int status; | 3159 | int status; |
| 3156 | struct ocfs2_mask_waiter mw; | 3160 | struct ocfs2_mask_waiter mw; |
| 3157 | unsigned long flags; | 3161 | unsigned long flags, flags2; |
| 3158 | 3162 | ||
| 3159 | ocfs2_init_mask_waiter(&mw); | 3163 | ocfs2_init_mask_waiter(&mw); |
| 3160 | 3164 | ||
| 3161 | spin_lock_irqsave(&lockres->l_lock, flags); | 3165 | spin_lock_irqsave(&lockres->l_lock, flags); |
| 3162 | lockres->l_flags |= OCFS2_LOCK_FREEING; | 3166 | lockres->l_flags |= OCFS2_LOCK_FREEING; |
| 3167 | if (lockres->l_flags & OCFS2_LOCK_QUEUED && current == osb->dc_task) { | ||
| 3168 | /* | ||
| 3169 | * We know the downconvert is queued but not in progress | ||
| 3170 | * because we are the downconvert thread and processing | ||
| 3171 | * different lock. So we can just remove the lock from the | ||
| 3172 | * queue. This is not only an optimization but also a way | ||
| 3173 | * to avoid the following deadlock: | ||
| 3174 | * ocfs2_dentry_post_unlock() | ||
| 3175 | * ocfs2_dentry_lock_put() | ||
| 3176 | * ocfs2_drop_dentry_lock() | ||
| 3177 | * iput() | ||
| 3178 | * ocfs2_evict_inode() | ||
| 3179 | * ocfs2_clear_inode() | ||
| 3180 | * ocfs2_mark_lockres_freeing() | ||
| 3181 | * ... blocks waiting for OCFS2_LOCK_QUEUED | ||
| 3182 | * since we are the downconvert thread which | ||
| 3183 | * should clear the flag. | ||
| 3184 | */ | ||
| 3185 | spin_unlock_irqrestore(&lockres->l_lock, flags); | ||
| 3186 | spin_lock_irqsave(&osb->dc_task_lock, flags2); | ||
| 3187 | list_del_init(&lockres->l_blocked_list); | ||
| 3188 | osb->blocked_lock_count--; | ||
| 3189 | spin_unlock_irqrestore(&osb->dc_task_lock, flags2); | ||
| 3190 | /* | ||
| 3191 | * Warn if we recurse into another post_unlock call. Strictly | ||
| 3192 | * speaking it isn't a problem but we need to be careful if | ||
| 3193 | * that happens (stack overflow, deadlocks, ...) so warn if | ||
| 3194 | * ocfs2 grows a path for which this can happen. | ||
| 3195 | */ | ||
| 3196 | WARN_ON_ONCE(lockres->l_ops->post_unlock); | ||
| 3197 | /* Since the lock is freeing we don't do much in the fn below */ | ||
| 3198 | ocfs2_process_blocked_lock(osb, lockres); | ||
| 3199 | return; | ||
| 3200 | } | ||
| 3163 | while (lockres->l_flags & OCFS2_LOCK_QUEUED) { | 3201 | while (lockres->l_flags & OCFS2_LOCK_QUEUED) { |
| 3164 | lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_QUEUED, 0); | 3202 | lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_QUEUED, 0); |
| 3165 | spin_unlock_irqrestore(&lockres->l_lock, flags); | 3203 | spin_unlock_irqrestore(&lockres->l_lock, flags); |
| @@ -3180,7 +3218,7 @@ void ocfs2_simple_drop_lockres(struct ocfs2_super *osb, | |||
| 3180 | { | 3218 | { |
| 3181 | int ret; | 3219 | int ret; |
| 3182 | 3220 | ||
| 3183 | ocfs2_mark_lockres_freeing(lockres); | 3221 | ocfs2_mark_lockres_freeing(osb, lockres); |
| 3184 | ret = ocfs2_drop_lock(osb, lockres); | 3222 | ret = ocfs2_drop_lock(osb, lockres); |
| 3185 | if (ret) | 3223 | if (ret) |
| 3186 | mlog_errno(ret); | 3224 | mlog_errno(ret); |
