1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* -*- mode: c; c-basic-offset: 8; -*-
3*4882a593Smuzhiyun * vim: noexpandtab sw=8 ts=8 sts=0:
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * dlmthread.c
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * standalone DLM module
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Copyright (C) 2004 Oracle. All rights reserved.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/fs.h>
15*4882a593Smuzhiyun #include <linux/types.h>
16*4882a593Smuzhiyun #include <linux/highmem.h>
17*4882a593Smuzhiyun #include <linux/init.h>
18*4882a593Smuzhiyun #include <linux/sysctl.h>
19*4882a593Smuzhiyun #include <linux/random.h>
20*4882a593Smuzhiyun #include <linux/blkdev.h>
21*4882a593Smuzhiyun #include <linux/socket.h>
22*4882a593Smuzhiyun #include <linux/inet.h>
23*4882a593Smuzhiyun #include <linux/timer.h>
24*4882a593Smuzhiyun #include <linux/kthread.h>
25*4882a593Smuzhiyun #include <linux/delay.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include "../cluster/heartbeat.h"
29*4882a593Smuzhiyun #include "../cluster/nodemanager.h"
30*4882a593Smuzhiyun #include "../cluster/tcp.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "dlmapi.h"
33*4882a593Smuzhiyun #include "dlmcommon.h"
34*4882a593Smuzhiyun #include "dlmdomain.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_THREAD)
37*4882a593Smuzhiyun #include "../cluster/masklog.h"
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static int dlm_thread(void *data);
40*4882a593Smuzhiyun static void dlm_flush_asts(struct dlm_ctxt *dlm);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* will exit holding res->spinlock, but may drop in function */
43*4882a593Smuzhiyun /* waits until flags are cleared on res->state */
__dlm_wait_on_lockres_flags(struct dlm_lock_resource * res,int flags)44*4882a593Smuzhiyun void __dlm_wait_on_lockres_flags(struct dlm_lock_resource *res, int flags)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun DECLARE_WAITQUEUE(wait, current);
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun add_wait_queue(&res->wq, &wait);
51*4882a593Smuzhiyun repeat:
52*4882a593Smuzhiyun set_current_state(TASK_UNINTERRUPTIBLE);
53*4882a593Smuzhiyun if (res->state & flags) {
54*4882a593Smuzhiyun spin_unlock(&res->spinlock);
55*4882a593Smuzhiyun schedule();
56*4882a593Smuzhiyun spin_lock(&res->spinlock);
57*4882a593Smuzhiyun goto repeat;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun remove_wait_queue(&res->wq, &wait);
60*4882a593Smuzhiyun __set_current_state(TASK_RUNNING);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
__dlm_lockres_has_locks(struct dlm_lock_resource * res)63*4882a593Smuzhiyun int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun if (list_empty(&res->granted) &&
66*4882a593Smuzhiyun list_empty(&res->converting) &&
67*4882a593Smuzhiyun list_empty(&res->blocked))
68*4882a593Smuzhiyun return 0;
69*4882a593Smuzhiyun return 1;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* "unused": the lockres has no locks, is not on the dirty list,
73*4882a593Smuzhiyun * has no inflight locks (in the gap between mastery and acquiring
74*4882a593Smuzhiyun * the first lock), and has no bits in its refmap.
75*4882a593Smuzhiyun * truly ready to be freed. */
__dlm_lockres_unused(struct dlm_lock_resource * res)76*4882a593Smuzhiyun int __dlm_lockres_unused(struct dlm_lock_resource *res)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun int bit;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (__dlm_lockres_has_locks(res))
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* Locks are in the process of being created */
86*4882a593Smuzhiyun if (res->inflight_locks)
87*4882a593Smuzhiyun return 0;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (!list_empty(&res->dirty) || res->state & DLM_LOCK_RES_DIRTY)
90*4882a593Smuzhiyun return 0;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (res->state & (DLM_LOCK_RES_RECOVERING|
93*4882a593Smuzhiyun DLM_LOCK_RES_RECOVERY_WAITING))
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* Another node has this resource with this node as the master */
97*4882a593Smuzhiyun bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
98*4882a593Smuzhiyun if (bit < O2NM_MAX_NODES)
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return 1;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* Call whenever you may have added or deleted something from one of
106*4882a593Smuzhiyun * the lockres queue's. This will figure out whether it belongs on the
107*4882a593Smuzhiyun * unused list or not and does the appropriate thing. */
__dlm_lockres_calc_usage(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)108*4882a593Smuzhiyun void __dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
109*4882a593Smuzhiyun struct dlm_lock_resource *res)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun assert_spin_locked(&dlm->spinlock);
112*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (__dlm_lockres_unused(res)){
115*4882a593Smuzhiyun if (list_empty(&res->purge)) {
116*4882a593Smuzhiyun mlog(0, "%s: Adding res %.*s to purge list\n",
117*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun res->last_used = jiffies;
120*4882a593Smuzhiyun dlm_lockres_get(res);
121*4882a593Smuzhiyun list_add_tail(&res->purge, &dlm->purge_list);
122*4882a593Smuzhiyun dlm->purge_count++;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun } else if (!list_empty(&res->purge)) {
125*4882a593Smuzhiyun mlog(0, "%s: Removing res %.*s from purge list\n",
126*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun list_del_init(&res->purge);
129*4882a593Smuzhiyun dlm_lockres_put(res);
130*4882a593Smuzhiyun dlm->purge_count--;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
dlm_lockres_calc_usage(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)134*4882a593Smuzhiyun void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
135*4882a593Smuzhiyun struct dlm_lock_resource *res)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
138*4882a593Smuzhiyun spin_lock(&res->spinlock);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun __dlm_lockres_calc_usage(dlm, res);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun spin_unlock(&res->spinlock);
143*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun * Do the real purge work:
148*4882a593Smuzhiyun * unhash the lockres, and
149*4882a593Smuzhiyun * clear flag DLM_LOCK_RES_DROPPING_REF.
150*4882a593Smuzhiyun * It requires dlm and lockres spinlock to be taken.
151*4882a593Smuzhiyun */
__dlm_do_purge_lockres(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)152*4882a593Smuzhiyun void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
153*4882a593Smuzhiyun struct dlm_lock_resource *res)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun assert_spin_locked(&dlm->spinlock);
156*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (!list_empty(&res->purge)) {
159*4882a593Smuzhiyun mlog(0, "%s: Removing res %.*s from purgelist\n",
160*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
161*4882a593Smuzhiyun list_del_init(&res->purge);
162*4882a593Smuzhiyun dlm_lockres_put(res);
163*4882a593Smuzhiyun dlm->purge_count--;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (!__dlm_lockres_unused(res)) {
167*4882a593Smuzhiyun mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
168*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
169*4882a593Smuzhiyun __dlm_print_one_lock_resource(res);
170*4882a593Smuzhiyun BUG();
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun __dlm_unhash_lockres(dlm, res);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun spin_lock(&dlm->track_lock);
176*4882a593Smuzhiyun if (!list_empty(&res->tracking))
177*4882a593Smuzhiyun list_del_init(&res->tracking);
178*4882a593Smuzhiyun else {
179*4882a593Smuzhiyun mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
180*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
181*4882a593Smuzhiyun __dlm_print_one_lock_resource(res);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun spin_unlock(&dlm->track_lock);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /*
186*4882a593Smuzhiyun * lockres is not in the hash now. drop the flag and wake up
187*4882a593Smuzhiyun * any processes waiting in dlm_get_lock_resource.
188*4882a593Smuzhiyun */
189*4882a593Smuzhiyun res->state &= ~DLM_LOCK_RES_DROPPING_REF;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
dlm_purge_lockres(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)192*4882a593Smuzhiyun static void dlm_purge_lockres(struct dlm_ctxt *dlm,
193*4882a593Smuzhiyun struct dlm_lock_resource *res)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun int master;
196*4882a593Smuzhiyun int ret = 0;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun assert_spin_locked(&dlm->spinlock);
199*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun master = (res->owner == dlm->node_num);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun mlog(0, "%s: Purging res %.*s, master %d\n", dlm->name,
204*4882a593Smuzhiyun res->lockname.len, res->lockname.name, master);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (!master) {
207*4882a593Smuzhiyun if (res->state & DLM_LOCK_RES_DROPPING_REF) {
208*4882a593Smuzhiyun mlog(ML_NOTICE, "%s: res %.*s already in DLM_LOCK_RES_DROPPING_REF state\n",
209*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
210*4882a593Smuzhiyun spin_unlock(&res->spinlock);
211*4882a593Smuzhiyun return;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun res->state |= DLM_LOCK_RES_DROPPING_REF;
215*4882a593Smuzhiyun /* drop spinlock... retake below */
216*4882a593Smuzhiyun spin_unlock(&res->spinlock);
217*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun spin_lock(&res->spinlock);
220*4882a593Smuzhiyun /* This ensures that clear refmap is sent after the set */
221*4882a593Smuzhiyun __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
222*4882a593Smuzhiyun spin_unlock(&res->spinlock);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* clear our bit from the master's refmap, ignore errors */
225*4882a593Smuzhiyun ret = dlm_drop_lockres_ref(dlm, res);
226*4882a593Smuzhiyun if (ret < 0) {
227*4882a593Smuzhiyun if (!dlm_is_host_down(ret))
228*4882a593Smuzhiyun BUG();
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
231*4882a593Smuzhiyun spin_lock(&res->spinlock);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (!list_empty(&res->purge)) {
235*4882a593Smuzhiyun mlog(0, "%s: Removing res %.*s from purgelist, master %d\n",
236*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name, master);
237*4882a593Smuzhiyun list_del_init(&res->purge);
238*4882a593Smuzhiyun dlm_lockres_put(res);
239*4882a593Smuzhiyun dlm->purge_count--;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (!master && ret == DLM_DEREF_RESPONSE_INPROG) {
243*4882a593Smuzhiyun mlog(0, "%s: deref %.*s in progress\n",
244*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
245*4882a593Smuzhiyun spin_unlock(&res->spinlock);
246*4882a593Smuzhiyun return;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun if (!__dlm_lockres_unused(res)) {
250*4882a593Smuzhiyun mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
251*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
252*4882a593Smuzhiyun __dlm_print_one_lock_resource(res);
253*4882a593Smuzhiyun BUG();
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun __dlm_unhash_lockres(dlm, res);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun spin_lock(&dlm->track_lock);
259*4882a593Smuzhiyun if (!list_empty(&res->tracking))
260*4882a593Smuzhiyun list_del_init(&res->tracking);
261*4882a593Smuzhiyun else {
262*4882a593Smuzhiyun mlog(ML_ERROR, "Resource %.*s not on the Tracking list\n",
263*4882a593Smuzhiyun res->lockname.len, res->lockname.name);
264*4882a593Smuzhiyun __dlm_print_one_lock_resource(res);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun spin_unlock(&dlm->track_lock);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* lockres is not in the hash now. drop the flag and wake up
269*4882a593Smuzhiyun * any processes waiting in dlm_get_lock_resource. */
270*4882a593Smuzhiyun if (!master) {
271*4882a593Smuzhiyun res->state &= ~DLM_LOCK_RES_DROPPING_REF;
272*4882a593Smuzhiyun spin_unlock(&res->spinlock);
273*4882a593Smuzhiyun wake_up(&res->wq);
274*4882a593Smuzhiyun } else
275*4882a593Smuzhiyun spin_unlock(&res->spinlock);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
dlm_run_purge_list(struct dlm_ctxt * dlm,int purge_now)278*4882a593Smuzhiyun static void dlm_run_purge_list(struct dlm_ctxt *dlm,
279*4882a593Smuzhiyun int purge_now)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun unsigned int run_max, unused;
282*4882a593Smuzhiyun unsigned long purge_jiffies;
283*4882a593Smuzhiyun struct dlm_lock_resource *lockres;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
286*4882a593Smuzhiyun run_max = dlm->purge_count;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun while(run_max && !list_empty(&dlm->purge_list)) {
289*4882a593Smuzhiyun run_max--;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun lockres = list_entry(dlm->purge_list.next,
292*4882a593Smuzhiyun struct dlm_lock_resource, purge);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun spin_lock(&lockres->spinlock);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun purge_jiffies = lockres->last_used +
297*4882a593Smuzhiyun msecs_to_jiffies(DLM_PURGE_INTERVAL_MS);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* Make sure that we want to be processing this guy at
300*4882a593Smuzhiyun * this time. */
301*4882a593Smuzhiyun if (!purge_now && time_after(purge_jiffies, jiffies)) {
302*4882a593Smuzhiyun /* Since resources are added to the purge list
303*4882a593Smuzhiyun * in tail order, we can stop at the first
304*4882a593Smuzhiyun * unpurgable resource -- anyone added after
305*4882a593Smuzhiyun * him will have a greater last_used value */
306*4882a593Smuzhiyun spin_unlock(&lockres->spinlock);
307*4882a593Smuzhiyun break;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /* Status of the lockres *might* change so double
311*4882a593Smuzhiyun * check. If the lockres is unused, holding the dlm
312*4882a593Smuzhiyun * spinlock will prevent people from getting and more
313*4882a593Smuzhiyun * refs on it. */
314*4882a593Smuzhiyun unused = __dlm_lockres_unused(lockres);
315*4882a593Smuzhiyun if (!unused ||
316*4882a593Smuzhiyun (lockres->state & DLM_LOCK_RES_MIGRATING) ||
317*4882a593Smuzhiyun (lockres->inflight_assert_workers != 0)) {
318*4882a593Smuzhiyun mlog(0, "%s: res %.*s is in use or being remastered, "
319*4882a593Smuzhiyun "used %d, state %d, assert master workers %u\n",
320*4882a593Smuzhiyun dlm->name, lockres->lockname.len,
321*4882a593Smuzhiyun lockres->lockname.name,
322*4882a593Smuzhiyun !unused, lockres->state,
323*4882a593Smuzhiyun lockres->inflight_assert_workers);
324*4882a593Smuzhiyun list_move_tail(&lockres->purge, &dlm->purge_list);
325*4882a593Smuzhiyun spin_unlock(&lockres->spinlock);
326*4882a593Smuzhiyun continue;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun dlm_lockres_get(lockres);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun dlm_purge_lockres(dlm, lockres);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun dlm_lockres_put(lockres);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* Avoid adding any scheduling latencies */
336*4882a593Smuzhiyun cond_resched_lock(&dlm->spinlock);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
dlm_shuffle_lists(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)342*4882a593Smuzhiyun static void dlm_shuffle_lists(struct dlm_ctxt *dlm,
343*4882a593Smuzhiyun struct dlm_lock_resource *res)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun struct dlm_lock *lock, *target;
346*4882a593Smuzhiyun int can_grant = 1;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /*
349*4882a593Smuzhiyun * Because this function is called with the lockres
350*4882a593Smuzhiyun * spinlock, and because we know that it is not migrating/
351*4882a593Smuzhiyun * recovering/in-progress, it is fine to reserve asts and
352*4882a593Smuzhiyun * basts right before queueing them all throughout
353*4882a593Smuzhiyun */
354*4882a593Smuzhiyun assert_spin_locked(&dlm->ast_lock);
355*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
356*4882a593Smuzhiyun BUG_ON((res->state & (DLM_LOCK_RES_MIGRATING|
357*4882a593Smuzhiyun DLM_LOCK_RES_RECOVERING|
358*4882a593Smuzhiyun DLM_LOCK_RES_IN_PROGRESS)));
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun converting:
361*4882a593Smuzhiyun if (list_empty(&res->converting))
362*4882a593Smuzhiyun goto blocked;
363*4882a593Smuzhiyun mlog(0, "%s: res %.*s has locks on the convert queue\n", dlm->name,
364*4882a593Smuzhiyun res->lockname.len, res->lockname.name);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun target = list_entry(res->converting.next, struct dlm_lock, list);
367*4882a593Smuzhiyun if (target->ml.convert_type == LKM_IVMODE) {
368*4882a593Smuzhiyun mlog(ML_ERROR, "%s: res %.*s converting lock to invalid mode\n",
369*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name);
370*4882a593Smuzhiyun BUG();
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun list_for_each_entry(lock, &res->granted, list) {
373*4882a593Smuzhiyun if (lock==target)
374*4882a593Smuzhiyun continue;
375*4882a593Smuzhiyun if (!dlm_lock_compatible(lock->ml.type,
376*4882a593Smuzhiyun target->ml.convert_type)) {
377*4882a593Smuzhiyun can_grant = 0;
378*4882a593Smuzhiyun /* queue the BAST if not already */
379*4882a593Smuzhiyun if (lock->ml.highest_blocked == LKM_IVMODE) {
380*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
381*4882a593Smuzhiyun __dlm_queue_bast(dlm, lock);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun /* update the highest_blocked if needed */
384*4882a593Smuzhiyun if (lock->ml.highest_blocked < target->ml.convert_type)
385*4882a593Smuzhiyun lock->ml.highest_blocked =
386*4882a593Smuzhiyun target->ml.convert_type;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun list_for_each_entry(lock, &res->converting, list) {
391*4882a593Smuzhiyun if (lock==target)
392*4882a593Smuzhiyun continue;
393*4882a593Smuzhiyun if (!dlm_lock_compatible(lock->ml.type,
394*4882a593Smuzhiyun target->ml.convert_type)) {
395*4882a593Smuzhiyun can_grant = 0;
396*4882a593Smuzhiyun if (lock->ml.highest_blocked == LKM_IVMODE) {
397*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
398*4882a593Smuzhiyun __dlm_queue_bast(dlm, lock);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun if (lock->ml.highest_blocked < target->ml.convert_type)
401*4882a593Smuzhiyun lock->ml.highest_blocked =
402*4882a593Smuzhiyun target->ml.convert_type;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /* we can convert the lock */
407*4882a593Smuzhiyun if (can_grant) {
408*4882a593Smuzhiyun spin_lock(&target->spinlock);
409*4882a593Smuzhiyun BUG_ON(target->ml.highest_blocked != LKM_IVMODE);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun mlog(0, "%s: res %.*s, AST for Converting lock %u:%llu, type "
412*4882a593Smuzhiyun "%d => %d, node %u\n", dlm->name, res->lockname.len,
413*4882a593Smuzhiyun res->lockname.name,
414*4882a593Smuzhiyun dlm_get_lock_cookie_node(be64_to_cpu(target->ml.cookie)),
415*4882a593Smuzhiyun dlm_get_lock_cookie_seq(be64_to_cpu(target->ml.cookie)),
416*4882a593Smuzhiyun target->ml.type,
417*4882a593Smuzhiyun target->ml.convert_type, target->ml.node);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun target->ml.type = target->ml.convert_type;
420*4882a593Smuzhiyun target->ml.convert_type = LKM_IVMODE;
421*4882a593Smuzhiyun list_move_tail(&target->list, &res->granted);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun BUG_ON(!target->lksb);
424*4882a593Smuzhiyun target->lksb->status = DLM_NORMAL;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun spin_unlock(&target->spinlock);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
429*4882a593Smuzhiyun __dlm_queue_ast(dlm, target);
430*4882a593Smuzhiyun /* go back and check for more */
431*4882a593Smuzhiyun goto converting;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun blocked:
435*4882a593Smuzhiyun if (list_empty(&res->blocked))
436*4882a593Smuzhiyun goto leave;
437*4882a593Smuzhiyun target = list_entry(res->blocked.next, struct dlm_lock, list);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun list_for_each_entry(lock, &res->granted, list) {
440*4882a593Smuzhiyun if (lock==target)
441*4882a593Smuzhiyun continue;
442*4882a593Smuzhiyun if (!dlm_lock_compatible(lock->ml.type, target->ml.type)) {
443*4882a593Smuzhiyun can_grant = 0;
444*4882a593Smuzhiyun if (lock->ml.highest_blocked == LKM_IVMODE) {
445*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
446*4882a593Smuzhiyun __dlm_queue_bast(dlm, lock);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun if (lock->ml.highest_blocked < target->ml.type)
449*4882a593Smuzhiyun lock->ml.highest_blocked = target->ml.type;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun list_for_each_entry(lock, &res->converting, list) {
454*4882a593Smuzhiyun if (lock==target)
455*4882a593Smuzhiyun continue;
456*4882a593Smuzhiyun if (!dlm_lock_compatible(lock->ml.type, target->ml.type)) {
457*4882a593Smuzhiyun can_grant = 0;
458*4882a593Smuzhiyun if (lock->ml.highest_blocked == LKM_IVMODE) {
459*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
460*4882a593Smuzhiyun __dlm_queue_bast(dlm, lock);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun if (lock->ml.highest_blocked < target->ml.type)
463*4882a593Smuzhiyun lock->ml.highest_blocked = target->ml.type;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* we can grant the blocked lock (only
468*4882a593Smuzhiyun * possible if converting list empty) */
469*4882a593Smuzhiyun if (can_grant) {
470*4882a593Smuzhiyun spin_lock(&target->spinlock);
471*4882a593Smuzhiyun BUG_ON(target->ml.highest_blocked != LKM_IVMODE);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun mlog(0, "%s: res %.*s, AST for Blocked lock %u:%llu, type %d, "
474*4882a593Smuzhiyun "node %u\n", dlm->name, res->lockname.len,
475*4882a593Smuzhiyun res->lockname.name,
476*4882a593Smuzhiyun dlm_get_lock_cookie_node(be64_to_cpu(target->ml.cookie)),
477*4882a593Smuzhiyun dlm_get_lock_cookie_seq(be64_to_cpu(target->ml.cookie)),
478*4882a593Smuzhiyun target->ml.type, target->ml.node);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /* target->ml.type is already correct */
481*4882a593Smuzhiyun list_move_tail(&target->list, &res->granted);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun BUG_ON(!target->lksb);
484*4882a593Smuzhiyun target->lksb->status = DLM_NORMAL;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun spin_unlock(&target->spinlock);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun __dlm_lockres_reserve_ast(res);
489*4882a593Smuzhiyun __dlm_queue_ast(dlm, target);
490*4882a593Smuzhiyun /* go back and check for more */
491*4882a593Smuzhiyun goto converting;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun leave:
495*4882a593Smuzhiyun return;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /* must have NO locks when calling this with res !=NULL * */
dlm_kick_thread(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)499*4882a593Smuzhiyun void dlm_kick_thread(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun if (res) {
502*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
503*4882a593Smuzhiyun spin_lock(&res->spinlock);
504*4882a593Smuzhiyun __dlm_dirty_lockres(dlm, res);
505*4882a593Smuzhiyun spin_unlock(&res->spinlock);
506*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun wake_up(&dlm->dlm_thread_wq);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
__dlm_dirty_lockres(struct dlm_ctxt * dlm,struct dlm_lock_resource * res)511*4882a593Smuzhiyun void __dlm_dirty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun assert_spin_locked(&dlm->spinlock);
514*4882a593Smuzhiyun assert_spin_locked(&res->spinlock);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* don't shuffle secondary queues */
517*4882a593Smuzhiyun if (res->owner == dlm->node_num) {
518*4882a593Smuzhiyun if (res->state & (DLM_LOCK_RES_MIGRATING |
519*4882a593Smuzhiyun DLM_LOCK_RES_BLOCK_DIRTY))
520*4882a593Smuzhiyun return;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (list_empty(&res->dirty)) {
523*4882a593Smuzhiyun /* ref for dirty_list */
524*4882a593Smuzhiyun dlm_lockres_get(res);
525*4882a593Smuzhiyun list_add_tail(&res->dirty, &dlm->dirty_list);
526*4882a593Smuzhiyun res->state |= DLM_LOCK_RES_DIRTY;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun mlog(0, "%s: res %.*s\n", dlm->name, res->lockname.len,
531*4882a593Smuzhiyun res->lockname.name);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun /* Launch the NM thread for the mounted volume */
dlm_launch_thread(struct dlm_ctxt * dlm)536*4882a593Smuzhiyun int dlm_launch_thread(struct dlm_ctxt *dlm)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun mlog(0, "Starting dlm_thread...\n");
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun dlm->dlm_thread_task = kthread_run(dlm_thread, dlm, "dlm-%s",
541*4882a593Smuzhiyun dlm->name);
542*4882a593Smuzhiyun if (IS_ERR(dlm->dlm_thread_task)) {
543*4882a593Smuzhiyun mlog_errno(PTR_ERR(dlm->dlm_thread_task));
544*4882a593Smuzhiyun dlm->dlm_thread_task = NULL;
545*4882a593Smuzhiyun return -EINVAL;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun return 0;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
dlm_complete_thread(struct dlm_ctxt * dlm)551*4882a593Smuzhiyun void dlm_complete_thread(struct dlm_ctxt *dlm)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun if (dlm->dlm_thread_task) {
554*4882a593Smuzhiyun mlog(ML_KTHREAD, "Waiting for dlm thread to exit\n");
555*4882a593Smuzhiyun kthread_stop(dlm->dlm_thread_task);
556*4882a593Smuzhiyun dlm->dlm_thread_task = NULL;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
dlm_dirty_list_empty(struct dlm_ctxt * dlm)560*4882a593Smuzhiyun static int dlm_dirty_list_empty(struct dlm_ctxt *dlm)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun int empty;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
565*4882a593Smuzhiyun empty = list_empty(&dlm->dirty_list);
566*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun return empty;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
dlm_flush_asts(struct dlm_ctxt * dlm)571*4882a593Smuzhiyun static void dlm_flush_asts(struct dlm_ctxt *dlm)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun int ret;
574*4882a593Smuzhiyun struct dlm_lock *lock;
575*4882a593Smuzhiyun struct dlm_lock_resource *res;
576*4882a593Smuzhiyun u8 hi;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun spin_lock(&dlm->ast_lock);
579*4882a593Smuzhiyun while (!list_empty(&dlm->pending_asts)) {
580*4882a593Smuzhiyun lock = list_entry(dlm->pending_asts.next,
581*4882a593Smuzhiyun struct dlm_lock, ast_list);
582*4882a593Smuzhiyun /* get an extra ref on lock */
583*4882a593Smuzhiyun dlm_lock_get(lock);
584*4882a593Smuzhiyun res = lock->lockres;
585*4882a593Smuzhiyun mlog(0, "%s: res %.*s, Flush AST for lock %u:%llu, type %d, "
586*4882a593Smuzhiyun "node %u\n", dlm->name, res->lockname.len,
587*4882a593Smuzhiyun res->lockname.name,
588*4882a593Smuzhiyun dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
589*4882a593Smuzhiyun dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
590*4882a593Smuzhiyun lock->ml.type, lock->ml.node);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun BUG_ON(!lock->ast_pending);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* remove from list (including ref) */
595*4882a593Smuzhiyun list_del_init(&lock->ast_list);
596*4882a593Smuzhiyun dlm_lock_put(lock);
597*4882a593Smuzhiyun spin_unlock(&dlm->ast_lock);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun if (lock->ml.node != dlm->node_num) {
600*4882a593Smuzhiyun ret = dlm_do_remote_ast(dlm, res, lock);
601*4882a593Smuzhiyun if (ret < 0)
602*4882a593Smuzhiyun mlog_errno(ret);
603*4882a593Smuzhiyun } else
604*4882a593Smuzhiyun dlm_do_local_ast(dlm, res, lock);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun spin_lock(&dlm->ast_lock);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /* possible that another ast was queued while
609*4882a593Smuzhiyun * we were delivering the last one */
610*4882a593Smuzhiyun if (!list_empty(&lock->ast_list)) {
611*4882a593Smuzhiyun mlog(0, "%s: res %.*s, AST queued while flushing last "
612*4882a593Smuzhiyun "one\n", dlm->name, res->lockname.len,
613*4882a593Smuzhiyun res->lockname.name);
614*4882a593Smuzhiyun } else
615*4882a593Smuzhiyun lock->ast_pending = 0;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* drop the extra ref.
618*4882a593Smuzhiyun * this may drop it completely. */
619*4882a593Smuzhiyun dlm_lock_put(lock);
620*4882a593Smuzhiyun dlm_lockres_release_ast(dlm, res);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun while (!list_empty(&dlm->pending_basts)) {
624*4882a593Smuzhiyun lock = list_entry(dlm->pending_basts.next,
625*4882a593Smuzhiyun struct dlm_lock, bast_list);
626*4882a593Smuzhiyun /* get an extra ref on lock */
627*4882a593Smuzhiyun dlm_lock_get(lock);
628*4882a593Smuzhiyun res = lock->lockres;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun BUG_ON(!lock->bast_pending);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /* get the highest blocked lock, and reset */
633*4882a593Smuzhiyun spin_lock(&lock->spinlock);
634*4882a593Smuzhiyun BUG_ON(lock->ml.highest_blocked <= LKM_IVMODE);
635*4882a593Smuzhiyun hi = lock->ml.highest_blocked;
636*4882a593Smuzhiyun lock->ml.highest_blocked = LKM_IVMODE;
637*4882a593Smuzhiyun spin_unlock(&lock->spinlock);
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun /* remove from list (including ref) */
640*4882a593Smuzhiyun list_del_init(&lock->bast_list);
641*4882a593Smuzhiyun dlm_lock_put(lock);
642*4882a593Smuzhiyun spin_unlock(&dlm->ast_lock);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun mlog(0, "%s: res %.*s, Flush BAST for lock %u:%llu, "
645*4882a593Smuzhiyun "blocked %d, node %u\n",
646*4882a593Smuzhiyun dlm->name, res->lockname.len, res->lockname.name,
647*4882a593Smuzhiyun dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
648*4882a593Smuzhiyun dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
649*4882a593Smuzhiyun hi, lock->ml.node);
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun if (lock->ml.node != dlm->node_num) {
652*4882a593Smuzhiyun ret = dlm_send_proxy_bast(dlm, res, lock, hi);
653*4882a593Smuzhiyun if (ret < 0)
654*4882a593Smuzhiyun mlog_errno(ret);
655*4882a593Smuzhiyun } else
656*4882a593Smuzhiyun dlm_do_local_bast(dlm, res, lock, hi);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun spin_lock(&dlm->ast_lock);
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun /* possible that another bast was queued while
661*4882a593Smuzhiyun * we were delivering the last one */
662*4882a593Smuzhiyun if (!list_empty(&lock->bast_list)) {
663*4882a593Smuzhiyun mlog(0, "%s: res %.*s, BAST queued while flushing last "
664*4882a593Smuzhiyun "one\n", dlm->name, res->lockname.len,
665*4882a593Smuzhiyun res->lockname.name);
666*4882a593Smuzhiyun } else
667*4882a593Smuzhiyun lock->bast_pending = 0;
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun /* drop the extra ref.
670*4882a593Smuzhiyun * this may drop it completely. */
671*4882a593Smuzhiyun dlm_lock_put(lock);
672*4882a593Smuzhiyun dlm_lockres_release_ast(dlm, res);
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun wake_up(&dlm->ast_wq);
675*4882a593Smuzhiyun spin_unlock(&dlm->ast_lock);
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun #define DLM_THREAD_TIMEOUT_MS (4 * 1000)
680*4882a593Smuzhiyun #define DLM_THREAD_MAX_DIRTY 100
681*4882a593Smuzhiyun
dlm_thread(void * data)682*4882a593Smuzhiyun static int dlm_thread(void *data)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun struct dlm_lock_resource *res;
685*4882a593Smuzhiyun struct dlm_ctxt *dlm = data;
686*4882a593Smuzhiyun unsigned long timeout = msecs_to_jiffies(DLM_THREAD_TIMEOUT_MS);
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun mlog(0, "dlm thread running for %s...\n", dlm->name);
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun while (!kthread_should_stop()) {
691*4882a593Smuzhiyun int n = DLM_THREAD_MAX_DIRTY;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /* dlm_shutting_down is very point-in-time, but that
694*4882a593Smuzhiyun * doesn't matter as we'll just loop back around if we
695*4882a593Smuzhiyun * get false on the leading edge of a state
696*4882a593Smuzhiyun * transition. */
697*4882a593Smuzhiyun dlm_run_purge_list(dlm, dlm_shutting_down(dlm));
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun /* We really don't want to hold dlm->spinlock while
700*4882a593Smuzhiyun * calling dlm_shuffle_lists on each lockres that
701*4882a593Smuzhiyun * needs to have its queues adjusted and AST/BASTs
702*4882a593Smuzhiyun * run. So let's pull each entry off the dirty_list
703*4882a593Smuzhiyun * and drop dlm->spinlock ASAP. Once off the list,
704*4882a593Smuzhiyun * res->spinlock needs to be taken again to protect
705*4882a593Smuzhiyun * the queues while calling dlm_shuffle_lists. */
706*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
707*4882a593Smuzhiyun while (!list_empty(&dlm->dirty_list)) {
708*4882a593Smuzhiyun int delay = 0;
709*4882a593Smuzhiyun res = list_entry(dlm->dirty_list.next,
710*4882a593Smuzhiyun struct dlm_lock_resource, dirty);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun /* peel a lockres off, remove it from the list,
713*4882a593Smuzhiyun * unset the dirty flag and drop the dlm lock */
714*4882a593Smuzhiyun BUG_ON(!res);
715*4882a593Smuzhiyun dlm_lockres_get(res);
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun spin_lock(&res->spinlock);
718*4882a593Smuzhiyun /* We clear the DLM_LOCK_RES_DIRTY state once we shuffle lists below */
719*4882a593Smuzhiyun list_del_init(&res->dirty);
720*4882a593Smuzhiyun spin_unlock(&res->spinlock);
721*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
722*4882a593Smuzhiyun /* Drop dirty_list ref */
723*4882a593Smuzhiyun dlm_lockres_put(res);
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun /* lockres can be re-dirtied/re-added to the
726*4882a593Smuzhiyun * dirty_list in this gap, but that is ok */
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun spin_lock(&dlm->ast_lock);
729*4882a593Smuzhiyun spin_lock(&res->spinlock);
730*4882a593Smuzhiyun if (res->owner != dlm->node_num) {
731*4882a593Smuzhiyun __dlm_print_one_lock_resource(res);
732*4882a593Smuzhiyun mlog(ML_ERROR, "%s: inprog %d, mig %d, reco %d,"
733*4882a593Smuzhiyun " dirty %d\n", dlm->name,
734*4882a593Smuzhiyun !!(res->state & DLM_LOCK_RES_IN_PROGRESS),
735*4882a593Smuzhiyun !!(res->state & DLM_LOCK_RES_MIGRATING),
736*4882a593Smuzhiyun !!(res->state & DLM_LOCK_RES_RECOVERING),
737*4882a593Smuzhiyun !!(res->state & DLM_LOCK_RES_DIRTY));
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun BUG_ON(res->owner != dlm->node_num);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /* it is now ok to move lockreses in these states
742*4882a593Smuzhiyun * to the dirty list, assuming that they will only be
743*4882a593Smuzhiyun * dirty for a short while. */
744*4882a593Smuzhiyun BUG_ON(res->state & DLM_LOCK_RES_MIGRATING);
745*4882a593Smuzhiyun if (res->state & (DLM_LOCK_RES_IN_PROGRESS |
746*4882a593Smuzhiyun DLM_LOCK_RES_RECOVERING |
747*4882a593Smuzhiyun DLM_LOCK_RES_RECOVERY_WAITING)) {
748*4882a593Smuzhiyun /* move it to the tail and keep going */
749*4882a593Smuzhiyun res->state &= ~DLM_LOCK_RES_DIRTY;
750*4882a593Smuzhiyun spin_unlock(&res->spinlock);
751*4882a593Smuzhiyun spin_unlock(&dlm->ast_lock);
752*4882a593Smuzhiyun mlog(0, "%s: res %.*s, inprogress, delay list "
753*4882a593Smuzhiyun "shuffle, state %d\n", dlm->name,
754*4882a593Smuzhiyun res->lockname.len, res->lockname.name,
755*4882a593Smuzhiyun res->state);
756*4882a593Smuzhiyun delay = 1;
757*4882a593Smuzhiyun goto in_progress;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun /* at this point the lockres is not migrating/
761*4882a593Smuzhiyun * recovering/in-progress. we have the lockres
762*4882a593Smuzhiyun * spinlock and do NOT have the dlm lock.
763*4882a593Smuzhiyun * safe to reserve/queue asts and run the lists. */
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /* called while holding lockres lock */
766*4882a593Smuzhiyun dlm_shuffle_lists(dlm, res);
767*4882a593Smuzhiyun res->state &= ~DLM_LOCK_RES_DIRTY;
768*4882a593Smuzhiyun spin_unlock(&res->spinlock);
769*4882a593Smuzhiyun spin_unlock(&dlm->ast_lock);
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun dlm_lockres_calc_usage(dlm, res);
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun in_progress:
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun spin_lock(&dlm->spinlock);
776*4882a593Smuzhiyun /* if the lock was in-progress, stick
777*4882a593Smuzhiyun * it on the back of the list */
778*4882a593Smuzhiyun if (delay) {
779*4882a593Smuzhiyun spin_lock(&res->spinlock);
780*4882a593Smuzhiyun __dlm_dirty_lockres(dlm, res);
781*4882a593Smuzhiyun spin_unlock(&res->spinlock);
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun dlm_lockres_put(res);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun /* unlikely, but we may need to give time to
786*4882a593Smuzhiyun * other tasks */
787*4882a593Smuzhiyun if (!--n) {
788*4882a593Smuzhiyun mlog(0, "%s: Throttling dlm thread\n",
789*4882a593Smuzhiyun dlm->name);
790*4882a593Smuzhiyun break;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun spin_unlock(&dlm->spinlock);
795*4882a593Smuzhiyun dlm_flush_asts(dlm);
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun /* yield and continue right away if there is more work to do */
798*4882a593Smuzhiyun if (!n) {
799*4882a593Smuzhiyun cond_resched();
800*4882a593Smuzhiyun continue;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun wait_event_interruptible_timeout(dlm->dlm_thread_wq,
804*4882a593Smuzhiyun !dlm_dirty_list_empty(dlm) ||
805*4882a593Smuzhiyun kthread_should_stop(),
806*4882a593Smuzhiyun timeout);
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun mlog(0, "quitting DLM thread\n");
810*4882a593Smuzhiyun return 0;
811*4882a593Smuzhiyun }
812