+struct ldlm_kms_shift_args {
+ __u64 old_kms;
+ __u64 kms;
+ bool complete;
+};
+
+/* Callback for interval_iterate functions, used by ldlm_extent_shift_Kms */
+static enum interval_iter ldlm_kms_shift_cb(struct interval_node *n,
+ void *args)
+{
+ struct ldlm_kms_shift_args *arg = args;
+ struct ldlm_interval *node = to_ldlm_interval(n);
+ struct ldlm_lock *tmplock;
+ struct ldlm_lock *lock = NULL;
+
+ ENTRY;
+
+ /* Since all locks in an interval have the same extent, we can just
+ * use the first lock without kms_ignore set. */
+ list_for_each_entry(tmplock, &node->li_group, l_sl_policy) {
+ if (ldlm_is_kms_ignore(tmplock))
+ continue;
+
+ lock = tmplock;
+
+ break;
+ }
+
+ /* No locks in this interval without kms_ignore set */
+ if (!lock)
+ RETURN(INTERVAL_ITER_CONT);
+
+ /* If we find a lock with a greater or equal kms, we are not the
+ * highest lock (or we share that distinction with another lock), and
+ * don't need to update KMS. Return old_kms and stop looking. */
+ if (lock->l_policy_data.l_extent.end >= arg->old_kms) {
+ arg->kms = arg->old_kms;
+ arg->complete = true;
+ RETURN(INTERVAL_ITER_STOP);
+ }
+
+ if (lock->l_policy_data.l_extent.end + 1 > arg->kms)
+ arg->kms = lock->l_policy_data.l_extent.end + 1;
+
+ /* Since interval_iterate_reverse starts with the highest lock and
+ * works down, for PW locks, we only need to check if we should update
+ * the kms, then stop walking the tree. PR locks are not exclusive, so
+ * the highest start does not imply the highest end and we must
+ * continue. (Only one group lock is allowed per resource, so this is
+ * irrelevant for group locks.)*/
+ if (lock->l_granted_mode == LCK_PW)
+ RETURN(INTERVAL_ITER_STOP);
+ else
+ RETURN(INTERVAL_ITER_CONT);
+}
+