staging/lustre/ldlm: Solve a race for LRU lock cancel
[cascardo/linux.git] / drivers / staging / lustre / lustre / ldlm / ldlm_request.c
index 9aa4c2d..5b0e396 100644 (file)
@@ -1369,6 +1369,7 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns,
 
        while (!list_empty(&ns->ns_unused_list)) {
                ldlm_policy_res_t result;
+               time_t last_use = 0;
 
                /* all unused locks */
                if (remained-- <= 0)
@@ -1387,6 +1388,10 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns,
                                /* already processed */
                                continue;
 
+                       last_use = lock->l_last_used;
+                       if (last_use == cfs_time_current())
+                               continue;
+
                        /* Somebody is already doing CANCEL. No need for this
                         * lock in LRU, do not traverse it again.
                         */
@@ -1434,11 +1439,13 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns,
                lock_res_and_lock(lock);
                /* Check flags again under the lock. */
                if ((lock->l_flags & LDLM_FL_CANCELING) ||
-                   (ldlm_lock_remove_from_lru(lock) == 0)) {
+                   (ldlm_lock_remove_from_lru_check(lock, last_use) == 0)) {
                        /* Another thread is removing lock from LRU, or
                         * somebody is already doing CANCEL, or there
                         * is a blocking request which will send cancel
-                        * by itself, or the lock is no longer unused.
+                        * by itself, or the lock is no longer unused or
+                        * the lock has been used since the pf() call and
+                        * pages could be put under it.
                         */
                        unlock_res_and_lock(lock);
                        lu_ref_del(&lock->l_reference,