Merge tag 'stable/for-linus-3.8-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / dlm / recover.c
index 4a7a76e42fc365e603e5ec9af26089ef9fe7d727..aedea28a86a1a145f2ed0c9a6eee180fe14fd259 100644 (file)
@@ -717,8 +717,14 @@ void dlm_recovered_lock(struct dlm_rsb *r)
  * the VALNOTVALID flag if necessary, and determining the correct lvb contents
  * based on the lvb's of the locks held on the rsb.
  *
- * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb.  If it
- * was already set prior to recovery, it's not cleared, regardless of locks.
+ * RSB_VALNOTVALID is set in two cases:
+ *
+ * 1. we are master, but not new, and we purged an EX/PW lock held by a
+ * failed node (in dlm_recover_purge which set RSB_RECOVER_LVB_INVAL)
+ *
+ * 2. we are a new master, and there are only NL/CR locks left.
+ * (We could probably improve this by only invaliding in this way when
+ * the previous master left uncleanly.  VMS docs mention that.)
  *
  * The LVB contents are only considered for changing when this is a new master
  * of the rsb (NEW_MASTER2).  Then, the rsb's lvb is taken from any lkb with
@@ -734,6 +740,19 @@ static void recover_lvb(struct dlm_rsb *r)
        int big_lock_exists = 0;
        int lvblen = r->res_ls->ls_lvblen;
 
+       if (!rsb_flag(r, RSB_NEW_MASTER2) &&
+           rsb_flag(r, RSB_RECOVER_LVB_INVAL)) {
+               /* case 1 above */
+               rsb_set_flag(r, RSB_VALNOTVALID);
+               return;
+       }
+
+       if (!rsb_flag(r, RSB_NEW_MASTER2))
+               return;
+
+       /* we are the new master, so figure out if VALNOTVALID should
+          be set, and set the rsb lvb from the best lkb available. */
+
        list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
                if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
                        continue;
@@ -772,13 +791,10 @@ static void recover_lvb(struct dlm_rsb *r)
        if (!lock_lvb_exists)
                goto out;
 
+       /* lvb is invalidated if only NL/CR locks remain */
        if (!big_lock_exists)
                rsb_set_flag(r, RSB_VALNOTVALID);
 
-       /* don't mess with the lvb unless we're the new master */
-       if (!rsb_flag(r, RSB_NEW_MASTER2))
-               goto out;
-
        if (!r->res_lvbptr) {
                r->res_lvbptr = dlm_allocate_lvb(r->res_ls);
                if (!r->res_lvbptr)
@@ -852,12 +868,19 @@ void dlm_recover_rsbs(struct dlm_ls *ls)
                if (is_master(r)) {
                        if (rsb_flag(r, RSB_RECOVER_CONVERT))
                                recover_conversion(r);
+
+                       /* recover lvb before granting locks so the updated
+                          lvb/VALNOTVALID is presented in the completion */
+                       recover_lvb(r);
+
                        if (rsb_flag(r, RSB_NEW_MASTER2))
                                recover_grant(r);
-                       recover_lvb(r);
                        count++;
+               } else {
+                       rsb_clear_flag(r, RSB_VALNOTVALID);
                }
                rsb_clear_flag(r, RSB_RECOVER_CONVERT);
+               rsb_clear_flag(r, RSB_RECOVER_LVB_INVAL);
                rsb_clear_flag(r, RSB_NEW_MASTER2);
                unlock_rsb(r);
        }