From: David Teigland <teigland@redhat.com> Subject: [RHEL5.1 PATCH] dlm: canceling deadlocked lock Date: Thu, 31 May 2007 09:36:28 -0500 Bugzilla: 238898 Message-Id: <20070531143628.GG2642@redhat.com> Changelog: [dlm] canceling deadlocked lock bz 238898 (4 of 4) Add a function that can be used through libdlm by a system daemon to cancel another process's deadlocked lock. A completion ast with EDEADLK is returned to the process waiting for the lock. upstream: gfs2-2.6-nmw.git and -mm Index: linux-rhel51-quilt/fs/dlm/dlm_internal.h =================================================================== --- linux-rhel51-quilt.orig/fs/dlm/dlm_internal.h 2007-06-08 10:17:28.000000000 -0500 +++ linux-rhel51-quilt/fs/dlm/dlm_internal.h 2007-06-08 10:18:13.000000000 -0500 @@ -216,6 +216,7 @@ #define DLM_IFL_ENDOFLIFE 0x00200000 #define DLM_IFL_WATCH_TIMEWARN 0x00400000 #define DLM_IFL_TIMEOUT_CANCEL 0x00800000 +#define DLM_IFL_DEADLOCK_CANCEL 0x01000000 #define DLM_IFL_USER 0x00000001 #define DLM_IFL_ORPHAN 0x00000002 Index: linux-rhel51-quilt/fs/dlm/lock.c =================================================================== --- linux-rhel51-quilt.orig/fs/dlm/lock.c 2007-06-08 10:14:50.000000000 -0500 +++ linux-rhel51-quilt/fs/dlm/lock.c 2007-06-08 10:18:13.000000000 -0500 @@ -300,6 +300,11 @@ rv = -ETIMEDOUT; } + if (rv == -DLM_ECANCEL && (lkb->lkb_flags & DLM_IFL_DEADLOCK_CANCEL)) { + lkb->lkb_flags &= ~DLM_IFL_DEADLOCK_CANCEL; + rv = -EDEADLK; + } + lkb->lkb_lksb->sb_status = rv; lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags; @@ -4450,6 +4455,54 @@ return error; } +int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + struct dlm_rsb *r; + int error; + + dlm_lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + + error = set_unlock_args(flags, ua, &args); + if (error) + goto out_put; + + /* same as cancel_lock(), but set DEADLOCK_CANCEL after lock_rsb */ + + r = lkb->lkb_resource; + hold_rsb(r); + lock_rsb(r); + + error = validate_unlock_args(lkb, &args); + if (error) + goto out_r; + lkb->lkb_flags |= DLM_IFL_DEADLOCK_CANCEL; + + error = _cancel_lock(r, lkb); + out_r: + unlock_rsb(r); + put_rsb(r); + + if (error == -DLM_ECANCEL) + error = 0; + /* from validate_unlock_args() */ + if (error == -EBUSY) + error = 0; + out_put: + dlm_put_lkb(lkb); + out: + dlm_unlock_recovery(ls); + return error; +} + /* lkb's that are removed from the waiters list by revert are just left on the orphans list with the granted orphan locks, to be freed by purge */ Index: linux-rhel51-quilt/fs/dlm/lock.h =================================================================== --- linux-rhel51-quilt.orig/fs/dlm/lock.h 2007-06-08 10:01:29.000000000 -0500 +++ linux-rhel51-quilt/fs/dlm/lock.h 2007-06-08 10:18:13.000000000 -0500 @@ -49,6 +49,7 @@ uint32_t flags, uint32_t lkid); int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc, int nodeid, int pid); +int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid); void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc); static inline int is_master(struct dlm_rsb *r) Index: linux-rhel51-quilt/fs/dlm/user.c =================================================================== --- linux-rhel51-quilt.orig/fs/dlm/user.c 2007-06-08 10:01:29.000000000 -0500 +++ linux-rhel51-quilt/fs/dlm/user.c 2007-06-08 10:18:13.000000000 -0500 @@ -155,6 +155,7 @@ return 1; case -DLM_ECANCEL: case -ETIMEDOUT: + case -EDEADLK: if (lkb->lkb_grmode == DLM_LOCK_IV) return 1; break; @@ -319,6 +320,22 @@ return error; } +static int device_user_deadlock(struct dlm_user_proc *proc, + struct dlm_lock_params *params) +{ + struct dlm_ls *ls; + int error; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + error = dlm_user_deadlock(ls, params->flags, params->lkid); + + dlm_put_lockspace(ls); + return error; +} + static int device_user_purge(struct dlm_user_proc *proc, struct dlm_purge_params *params) { @@ -530,6 +547,14 @@ error = device_user_unlock(proc, &kbuf->i.lock); break; + case DLM_USER_DEADLOCK: + if (!proc) { + log_print("no locking on control device"); + goto out_sig; + } + error = device_user_deadlock(proc, &kbuf->i.lock); + break; + case DLM_USER_CREATE_LOCKSPACE: if (proc) { log_print("create/remove only on control device"); Index: linux-rhel51-quilt/include/linux/dlm_device.h =================================================================== --- linux-rhel51-quilt.orig/include/linux/dlm_device.h 2007-06-08 10:01:29.000000000 -0500 +++ linux-rhel51-quilt/include/linux/dlm_device.h 2007-06-08 10:18:13.000000000 -0500 @@ -92,6 +92,7 @@ #define DLM_USER_CREATE_LOCKSPACE 4 #define DLM_USER_REMOVE_LOCKSPACE 5 #define DLM_USER_PURGE 6 +#define DLM_USER_DEADLOCK 7 /* Arbitrary length restriction */ #define MAX_LS_NAME_LEN 64