[Linux-cluster] Deadlock detection in libdlm

Steve Little steve.little at gmail.com
Tue Jan 25 20:01:00 UTC 2011


I've been trying to make use of deadlock detection in libdlm, but
without any luck so far. I'm hoping someone can tell me what I'm doing
wrong, or how to debug this further.

My test code looks like this:

#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define _REENTRANT
#include <libdlm.h>

void lock(struct dlm_lksb *l, const char *name, int mode) {
  printf("[%d] Attempting to lock %s, mode %d\n",getpid(),name,mode);
  int status = dlm_lock_wait(LKM_NLMODE, l, LKF_EXPEDITE, name, strlen(name),
                            0, NULL, NULL, NULL);
  if(status != 0) abort();

  status = dlm_lock_wait(mode, l, LKF_CONVERT | LKF_CONVDEADLK, name,
strlen(name),
                            0, NULL, NULL, NULL);
  if(status == 0) status = l->sb_status;

  printf("[%d] Status was %d\n",getpid(),status);
}

int main(void) {

  pid_t pid = fork();

  if(pid == 0) { // child process
    if(dlm_pthread_init() != 0) abort();

    struct dlm_lksb l1,l2;
    memset(&l1,0,sizeof(l1));
    memset(&l2,0,sizeof(l2));

    lock(&l1,"A",LKM_PRMODE);

    lock(&l2,"B",LKM_EXMODE);

    dlm_unlock_wait(l1.sb_lkid,0,&l1);
    dlm_unlock_wait(l2.sb_lkid,0,&l2);
    return EXIT_SUCCESS;
  } else { // parent process
    if(dlm_pthread_init() != 0) abort();

    struct dlm_lksb l1,l2;
    memset(&l1,0,sizeof(l1));
    memset(&l2,0,sizeof(l2));

    lock(&l1,"B",LKM_PRMODE);

    sleep(5); // wait to ensure child has grabbed A
    lock(&l2,"A",LKM_EXMODE);

    dlm_unlock_wait(l2.sb_lkid,0,&l2);
    dlm_unlock_wait(l1.sb_lkid,0,&l1);
  }

  return EXIT_SUCCESS;
}

This should cause a classic deadlock: process 1 is waiting on resource
A, which is locked by process 2. Process 2 is waiting on resource B,
which is locked by process 1.

>From the manpage, I would expect this to be detected and resolved by
one of the lock requests being refused:

"Return values
      *snip*
       EDEADLOCK       The lock operation is causing a deadlock and has been
                       cancelled. If this was a conversion then the lock is
                       reverted to its previously granted state. If it was a
                       new lock then it has not been granted. (NB Only
                       conversion deadlocks are currently detected)"

But instead, the process hangs indefinitely, until I kill it:


$ ./a.out
[27986] Attempting to lock A, mode 3
[27985] Attempting to lock B, mode 3
[27986] Status was 0
[27986] Attempting to lock B, mode 5
[27985] Status was 0
[27985] Attempting to lock A, mode 5
<hangs here>

Here's the output of lockdump:

$ /sbin/dlm_tool lockdump default
id 01aa0005 gr PR rq IV pid 27986 master 2 "A"
id 034f0004 gr NL rq EX pid 27985 master 2 "A"
id 03630001 gr PR rq IV pid 27985 master 4 "B"
id 02070004 gr NL rq EX pid 27986 master 4 "B"

and lockdebug:

$ /sbin/dlm_tool lockdebug default

Resource ffff810c1f02c080 Name (len=1) "A"
Local Copy, Master is node 2
Granted Queue
01aa0005 PR Master:     03b80003
Conversion Queue
034f0004 NL (EX) Master:     02310005
Waiting Queue

Resource ffff810c1f02cc80 Name (len=1) "B"
Local Copy, Master is node 4
Granted Queue
03630001 PR Master:     030c0001
Conversion Queue
02070004 NL (EX) Master:     03530003
Waiting Queue

The machine I'm using is running RHEL5.




More information about the Linux-cluster mailing list