diff options
author | Kurt Hackel <kurt.hackel@oracle.com> | 2006-12-01 17:47:20 -0500 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-02-07 14:53:07 -0500 |
commit | ba2bf2185121db74e075c703fbf986761733dd1d (patch) | |
tree | f7b90fa14db61fb6fc5d92d393b1d837e58a9faa /fs/ocfs2/dlm/dlmdomain.c | |
parent | 5331be090567d9335476f876b2d85427cd7c4426 (diff) |
ocfs2_dlm: fix cluster-wide refcounting of lock resources
This was previously broken and migration of some locks had to be temporarily
disabled. We use a new (and backward-incompatible) set of network messages
to account for all references to a lock resources held across the cluster.
once these are all freed, the master node may then free the lock resource
memory once its local references are dropped.
Signed-off-by: Kurt Hackel <kurt.hackel@oracle.com>
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/ocfs2/dlm/dlmdomain.c')
-rw-r--r-- | fs/ocfs2/dlm/dlmdomain.c | 117 |
1 files changed, 87 insertions, 30 deletions
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index f0b25f2dd205..3995de360264 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c | |||
@@ -125,10 +125,10 @@ void __dlm_insert_lockres(struct dlm_ctxt *dlm, | |||
125 | hlist_add_head(&res->hash_node, bucket); | 125 | hlist_add_head(&res->hash_node, bucket); |
126 | } | 126 | } |
127 | 127 | ||
128 | struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, | 128 | struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm, |
129 | const char *name, | 129 | const char *name, |
130 | unsigned int len, | 130 | unsigned int len, |
131 | unsigned int hash) | 131 | unsigned int hash) |
132 | { | 132 | { |
133 | struct hlist_head *bucket; | 133 | struct hlist_head *bucket; |
134 | struct hlist_node *list; | 134 | struct hlist_node *list; |
@@ -154,6 +154,37 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, | |||
154 | return NULL; | 154 | return NULL; |
155 | } | 155 | } |
156 | 156 | ||
157 | /* intended to be called by functions which do not care about lock | ||
158 | * resources which are being purged (most net _handler functions). | ||
159 | * this will return NULL for any lock resource which is found but | ||
160 | * currently in the process of dropping its mastery reference. | ||
161 | * use __dlm_lookup_lockres_full when you need the lock resource | ||
162 | * regardless (e.g. dlm_get_lock_resource) */ | ||
163 | struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, | ||
164 | const char *name, | ||
165 | unsigned int len, | ||
166 | unsigned int hash) | ||
167 | { | ||
168 | struct dlm_lock_resource *res = NULL; | ||
169 | |||
170 | mlog_entry("%.*s\n", len, name); | ||
171 | |||
172 | assert_spin_locked(&dlm->spinlock); | ||
173 | |||
174 | res = __dlm_lookup_lockres_full(dlm, name, len, hash); | ||
175 | if (res) { | ||
176 | spin_lock(&res->spinlock); | ||
177 | if (res->state & DLM_LOCK_RES_DROPPING_REF) { | ||
178 | spin_unlock(&res->spinlock); | ||
179 | dlm_lockres_put(res); | ||
180 | return NULL; | ||
181 | } | ||
182 | spin_unlock(&res->spinlock); | ||
183 | } | ||
184 | |||
185 | return res; | ||
186 | } | ||
187 | |||
157 | struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm, | 188 | struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm, |
158 | const char *name, | 189 | const char *name, |
159 | unsigned int len) | 190 | unsigned int len) |
@@ -330,43 +361,60 @@ static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) | |||
330 | wake_up(&dlm_domain_events); | 361 | wake_up(&dlm_domain_events); |
331 | } | 362 | } |
332 | 363 | ||
333 | static void dlm_migrate_all_locks(struct dlm_ctxt *dlm) | 364 | static int dlm_migrate_all_locks(struct dlm_ctxt *dlm) |
334 | { | 365 | { |
335 | int i; | 366 | int i, num, n, ret = 0; |
336 | struct dlm_lock_resource *res; | 367 | struct dlm_lock_resource *res; |
368 | struct hlist_node *iter; | ||
369 | struct hlist_head *bucket; | ||
370 | int dropped; | ||
337 | 371 | ||
338 | mlog(0, "Migrating locks from domain %s\n", dlm->name); | 372 | mlog(0, "Migrating locks from domain %s\n", dlm->name); |
339 | restart: | 373 | |
374 | num = 0; | ||
340 | spin_lock(&dlm->spinlock); | 375 | spin_lock(&dlm->spinlock); |
341 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { | 376 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { |
342 | while (!hlist_empty(dlm_lockres_hash(dlm, i))) { | 377 | redo_bucket: |
343 | res = hlist_entry(dlm_lockres_hash(dlm, i)->first, | 378 | n = 0; |
344 | struct dlm_lock_resource, hash_node); | 379 | bucket = dlm_lockres_hash(dlm, i); |
345 | /* need reference when manually grabbing lockres */ | 380 | iter = bucket->first; |
381 | while (iter) { | ||
382 | n++; | ||
383 | res = hlist_entry(iter, struct dlm_lock_resource, | ||
384 | hash_node); | ||
346 | dlm_lockres_get(res); | 385 | dlm_lockres_get(res); |
347 | /* this should unhash the lockres | 386 | /* migrate, if necessary. this will drop the dlm |
348 | * and exit with dlm->spinlock */ | 387 | * spinlock and retake it if it does migration. */ |
349 | mlog(0, "purging res=%p\n", res); | 388 | dropped = dlm_empty_lockres(dlm, res); |
350 | if (dlm_lockres_is_dirty(dlm, res)) { | 389 | |
351 | /* HACK! this should absolutely go. | 390 | spin_lock(&res->spinlock); |
352 | * need to figure out why some empty | 391 | __dlm_lockres_calc_usage(dlm, res); |
353 | * lockreses are still marked dirty */ | 392 | iter = res->hash_node.next; |
354 | mlog(ML_ERROR, "lockres %.*s dirty!\n", | 393 | spin_unlock(&res->spinlock); |
355 | res->lockname.len, res->lockname.name); | 394 | |
356 | |||
357 | spin_unlock(&dlm->spinlock); | ||
358 | dlm_kick_thread(dlm, res); | ||
359 | wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res)); | ||
360 | dlm_lockres_put(res); | ||
361 | goto restart; | ||
362 | } | ||
363 | dlm_purge_lockres(dlm, res); | ||
364 | dlm_lockres_put(res); | 395 | dlm_lockres_put(res); |
396 | |||
397 | cond_resched_lock(&dlm->spinlock); | ||
398 | |||
399 | if (dropped) | ||
400 | goto redo_bucket; | ||
365 | } | 401 | } |
402 | num += n; | ||
403 | mlog(0, "%s: touched %d lockreses in bucket %d " | ||
404 | "(tot=%d)\n", dlm->name, n, i, num); | ||
366 | } | 405 | } |
367 | spin_unlock(&dlm->spinlock); | 406 | spin_unlock(&dlm->spinlock); |
368 | 407 | wake_up(&dlm->dlm_thread_wq); | |
408 | |||
409 | /* let the dlm thread take care of purging, keep scanning until | ||
410 | * nothing remains in the hash */ | ||
411 | if (num) { | ||
412 | mlog(0, "%s: %d lock resources in hash last pass\n", | ||
413 | dlm->name, num); | ||
414 | ret = -EAGAIN; | ||
415 | } | ||
369 | mlog(0, "DONE Migrating locks from domain %s\n", dlm->name); | 416 | mlog(0, "DONE Migrating locks from domain %s\n", dlm->name); |
417 | return ret; | ||
370 | } | 418 | } |
371 | 419 | ||
372 | static int dlm_no_joining_node(struct dlm_ctxt *dlm) | 420 | static int dlm_no_joining_node(struct dlm_ctxt *dlm) |
@@ -571,7 +619,9 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) | |||
571 | /* We changed dlm state, notify the thread */ | 619 | /* We changed dlm state, notify the thread */ |
572 | dlm_kick_thread(dlm, NULL); | 620 | dlm_kick_thread(dlm, NULL); |
573 | 621 | ||
574 | dlm_migrate_all_locks(dlm); | 622 | while (dlm_migrate_all_locks(dlm)) { |
623 | mlog(0, "%s: more migration to do\n", dlm->name); | ||
624 | } | ||
575 | dlm_mark_domain_leaving(dlm); | 625 | dlm_mark_domain_leaving(dlm); |
576 | dlm_leave_domain(dlm); | 626 | dlm_leave_domain(dlm); |
577 | dlm_complete_dlm_shutdown(dlm); | 627 | dlm_complete_dlm_shutdown(dlm); |
@@ -1082,6 +1132,13 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm) | |||
1082 | if (status) | 1132 | if (status) |
1083 | goto bail; | 1133 | goto bail; |
1084 | 1134 | ||
1135 | status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key, | ||
1136 | sizeof(struct dlm_deref_lockres), | ||
1137 | dlm_deref_lockres_handler, | ||
1138 | dlm, &dlm->dlm_domain_handlers); | ||
1139 | if (status) | ||
1140 | goto bail; | ||
1141 | |||
1085 | status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key, | 1142 | status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key, |
1086 | sizeof(struct dlm_migrate_request), | 1143 | sizeof(struct dlm_migrate_request), |
1087 | dlm_migrate_request_handler, | 1144 | dlm_migrate_request_handler, |