1 /*
2 * Copyright 2004-2011 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 */
9
10 #ifdef _REENTRANT
11 #include <pthread.h>
12 #endif
13 #include <sys/types.h>
14 #include <sys/ioctl.h>
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <inttypes.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <dirent.h>
26 #include <linux/major.h>
27 #include <sys/sysmacros.h>
28 #ifdef HAVE_SELINUX
29 #include <selinux/selinux.h>
30 #endif
31 #include <linux/types.h>
32 #include <linux/dlm.h>
33 #define BUILDING_LIBDLM
34 #include "libdlm.h"
35 #include <linux/dlm_device.h>
36
37 #define MISC_PREFIX "/dev/misc/"
38 #define DLM_PREFIX "dlm_"
39 #define DLM_MISC_PREFIX MISC_PREFIX DLM_PREFIX
40 #define DLM_CONTROL_NAME "dlm-control"
41 #define DLM_CONTROL_PATH MISC_PREFIX DLM_CONTROL_NAME
42 #define DEFAULT_LOCKSPACE "default"
43
44 /*
45 * V5 of the dlm_device.h kernel/user interface structs
46 */
47
48 struct dlm_lock_params_v5 {
49 __u8 mode;
50 __u8 namelen;
51 __u16 flags;
52 __u32 lkid;
53 __u32 parent;
54 void *castparam;
55 void *castaddr;
56 void *bastparam;
57 void *bastaddr;
58 struct dlm_lksb *lksb;
59 char lvb[DLM_USER_LVB_LEN];
60 char name[0];
61 };
62
63 struct dlm_write_request_v5 {
64 __u32 version[3];
65 __u8 cmd;
66 __u8 is64bit;
67 __u8 unused[2];
68
69 union {
70 struct dlm_lock_params_v5 lock;
71 struct dlm_lspace_params lspace;
72 } i;
73 };
74
75 struct dlm_lock_result_v5 {
76 __u32 length;
77 void *user_astaddr;
78 void *user_astparam;
79 struct dlm_lksb *user_lksb;
80 struct dlm_lksb lksb;
81 __u8 bast_mode;
82 __u8 unused[3];
83 /* Offsets may be zero if no data is present */
84 __u32 lvb_offset;
85 };
86
87
88 /*
89 * One of these per lockspace in use by the application
90 */
91
92 struct dlm_ls_info {
93 int fd;
94 #ifdef _REENTRANT
95 pthread_t tid;
96 #else
97 int tid;
98 #endif
99 };
100
101 /*
102 * The default lockspace.
103 * I've resisted putting locking around this as the user should be
104 * "sensible" and only do lockspace operations either in the
105 * main thread or ... carefully...
106 */
107
108 static struct dlm_ls_info *default_ls = NULL;
109 static int control_fd = -1;
110 static struct dlm_device_version kernel_version;
111 static int kernel_version_detected = 0;
112
113
114 static int release_lockspace(uint32_t minor, uint32_t flags);
115
116
117 static void ls_dev_name(const char *lsname, char *devname, int devlen)
118 {
119 snprintf(devname, devlen, DLM_MISC_PREFIX "%s", lsname);
120 }
121
122 static void dummy_ast_routine(void *arg)
123 {
124 }
125
126 #ifdef _REENTRANT
127 /* Used for the synchronous and "simplified, synchronous" API routines */
128 struct lock_wait
129 {
130 pthread_cond_t cond;
131 pthread_mutex_t mutex;
132 struct dlm_lksb lksb;
133 };
134
135 static void sync_ast_routine(void *arg)
136 {
137 struct lock_wait *lwait = arg;
138
139 pthread_mutex_lock(&lwait->mutex);
140 pthread_cond_signal(&lwait->cond);
141 pthread_mutex_unlock(&lwait->mutex);
142 }
143
144 /* lock_resource & unlock_resource
145 * are the simplified, synchronous API.
146 * Aways uses the default lockspace.
147 */
148 int lock_resource(const char *resource, int mode, int flags, int *lockid)
149 {
150 int status;
151 struct lock_wait lwait;
152
153 if (default_ls == NULL)
154 {
155 if (dlm_pthread_init())
156 {
157 return -1;
158 }
159 }
160
161 if (!lockid)
162 {
163 errno = EINVAL;
164 return -1;
165 }
166
167 /* Conversions need the lockid in the LKSB */
168 if (flags & LKF_CONVERT)
169 lwait.lksb.sb_lkid = *lockid;
170
171 pthread_cond_init(&lwait.cond, NULL);
172 pthread_mutex_init(&lwait.mutex, NULL);
173 pthread_mutex_lock(&lwait.mutex);
174
175 status = dlm_lock(mode,
176 &lwait.lksb,
177 flags,
178 resource,
179 strlen(resource),
180 0,
181 sync_ast_routine,
182 &lwait,
183 NULL,
184 NULL);
185 if (status)
186 return status;
187
188 /* Wait for it to complete */
189 pthread_cond_wait(&lwait.cond, &lwait.mutex);
190 pthread_mutex_unlock(&lwait.mutex);
191
192 *lockid = lwait.lksb.sb_lkid;
193
194 errno = lwait.lksb.sb_status;
195 if (lwait.lksb.sb_status)
196 return -1;
197 else
198 return 0;
199 }
200
201
202 int unlock_resource(int lockid)
203 {
204 int status;
205 struct lock_wait lwait;
206
207 if (default_ls == NULL)
208 {
209 errno = -ENOTCONN;
210 return -1;
211 }
212
213 pthread_cond_init(&lwait.cond, NULL);
214 pthread_mutex_init(&lwait.mutex, NULL);
215 pthread_mutex_lock(&lwait.mutex);
216
217 status = dlm_unlock(lockid, 0, &lwait.lksb, &lwait);
218
219 if (status)
220 return status;
221
222 /* Wait for it to complete */
223 pthread_cond_wait(&lwait.cond, &lwait.mutex);
224 pthread_mutex_unlock(&lwait.mutex);
225
226 errno = lwait.lksb.sb_status;
227 if (lwait.lksb.sb_status != DLM_EUNLOCK)
228 return -1;
229 else
230 return 0;
231 }
232
233 /* Tidy up threads after a lockspace is closed */
234 static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
235 {
236 int status = 0;
237 int fd;
238
239 /* Must close the fd after the thread has finished */
240 fd = lsinfo->fd;
241 if (lsinfo->tid)
242 {
243 status = pthread_cancel(lsinfo->tid);
244 if (!status)
245 pthread_join(lsinfo->tid, NULL);
246 }
247 if (!status)
248 {
249 free(lsinfo);
250 close(fd);
251 }
252
253 return status;
254 }
255
256 /* Cleanup default lockspace */
257 int dlm_pthread_cleanup(void)
258 {
259 struct dlm_ls_info *lsinfo = default_ls;
260
261 /* Protect users from their own stupidity */
262 if (!lsinfo)
263 return 0;
264
265 default_ls = NULL;
266
267 return ls_pthread_cleanup(lsinfo);
268 }
269 #else
270
271 /* Non-pthread version of cleanup */
272 static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
273 {
274 close(lsinfo->fd);
275 free(lsinfo);
276 return 0;
277 }
278 #endif
279
280
281 static void set_version_v5(struct dlm_write_request_v5 *req)
282 {
283 req->version[0] = kernel_version.version[0];
284 req->version[1] = kernel_version.version[1];
285 req->version[2] = kernel_version.version[2];
286 if (sizeof(long) == sizeof(long long))
287 req->is64bit = 1;
288 else
289 req->is64bit = 0;
290 }
291
292 static void set_version_v6(struct dlm_write_request *req)
293 {
294 req->version[0] = kernel_version.version[0];
295 req->version[1] = kernel_version.version[1];
296 req->version[2] = kernel_version.version[2];
297 if (sizeof(long) == sizeof(long long))
298 req->is64bit = 1;
299 else
300 req->is64bit = 0;
301 }
302
303 static int open_default_lockspace(void)
304 {
305 if (!default_ls) {
306 dlm_lshandle_t ls;
307
308 /* This isn't the race it looks, create_lockspace will
309 * do the right thing if the lockspace has already been
310 * created.
311 */
312
313 ls = dlm_open_lockspace(DEFAULT_LOCKSPACE);
314 if (!ls)
315 ls = dlm_create_lockspace(DEFAULT_LOCKSPACE, 0600);
316 if (!ls)
317 return -1;
318
319 default_ls = (struct dlm_ls_info *)ls;
320 }
321 return 0;
322 }
323
324 static void detect_kernel_version(void)
325 {
326 struct dlm_device_version v;
327 int rv;
328
329 rv = read(control_fd, &v, sizeof(struct dlm_device_version));
330 if (rv < 0) {
331 kernel_version.version[0] = 5;
332 kernel_version.version[1] = 0;
333 kernel_version.version[2] = 0;
334 } else {
335 kernel_version.version[0] = v.version[0];
336 kernel_version.version[1] = v.version[1];
337 kernel_version.version[2] = v.version[2];
338 }
339
340 kernel_version_detected = 1;
341 }
342
343 static int find_control_minor(int *minor)
344 {
345 FILE *f;
346 char name[256];
347 int found = 0, m = 0;
348
349 f = fopen("/proc/misc", "r");
350 if (!f)
351 return -1;
352
353 while (!feof(f)) {
354 if (fscanf(f, "%d %s", &m, name) != 2)
355 continue;
356 if (strcmp(name, DLM_CONTROL_NAME))
357 continue;
358 found = 1;
359 break;
360 }
361 fclose(f);
362
363 if (found) {
364 *minor = m;
365 return 0;
366 }
367 return -1;
368 }
369
370 static int open_control_device(void)
371 {
372 struct stat st;
373 int i, rv, minor, found = 0;
374
375 if (control_fd > -1)
376 goto out;
377
378 rv = find_control_minor(&minor);
379 if (rv < 0)
380 return -1;
381
382 /* wait for udev to create the device */
383
384 for (i = 0; i < 10; i++) {
385 if (stat(DLM_CONTROL_PATH, &st) == 0 &&
386 minor(st.st_rdev) == minor) {
387 found = 1;
388 break;
389 }
390 sleep(1);
391 continue;
392 }
393
394 if (!found)
395 return -1;
396
397 control_fd = open(DLM_CONTROL_PATH, O_RDWR);
398 if (control_fd == -1)
399 return -1;
400
401 out:
402 fcntl(control_fd, F_SETFD, 1);
403
404 if (!kernel_version_detected)
405 detect_kernel_version();
406 return 0;
407 }
408
409 /* the max number of characters in a sysfs device name, not including \0 */
410 #define MAX_SYSFS_NAME 19
411
412 static int find_udev_device(const char *lockspace, int minor, char *udev_path)
413 {
414 char bname[PATH_MAX];
415 char tmp_path[PATH_MAX];
416 DIR *d;
417 struct dirent *de;
418 struct stat st;
419 size_t basename_len;
420 int i;
421
422 ls_dev_name(lockspace, udev_path, PATH_MAX);
423 snprintf(bname, PATH_MAX, DLM_PREFIX "%s", lockspace);
424 basename_len = strlen(bname);
425
426 for (i = 0; i < 10; i++) {
427
428 /* look for a device with the full name */
429
430 if (stat(udev_path, &st) == 0 && minor(st.st_rdev) == minor)
431 return 0;
432
433 if (basename_len < MAX_SYSFS_NAME) {
434 sleep(1);
435 continue;
436 }
437
438 /* look for a device with a truncated name */
439
440 d = opendir(MISC_PREFIX);
441 while ((de = readdir(d))) {
442 if (de->d_name[0] == '.')
443 continue;
444 if (strlen(de->d_name) < MAX_SYSFS_NAME)
445 continue;
446 if (strncmp(de->d_name, bname, MAX_SYSFS_NAME))
447 continue;
448 snprintf(tmp_path, PATH_MAX, MISC_PREFIX "%s",
449 de->d_name);
450 if (stat(tmp_path, &st))
451 continue;
452 if (minor(st.st_rdev) != minor)
453 continue;
454
455 /* truncated name */
456 strncpy(udev_path, tmp_path, PATH_MAX);
457 closedir(d);
458 return 0;
459 }
460 closedir(d);
461 sleep(1);
462 }
463
464 return -1;
465 }
466
467 /*
468 * do_dlm_dispatch()
469 * Read an ast from the kernel.
470 */
471
472 static int do_dlm_dispatch_v5(int fd)
473 {
474 char resultbuf[sizeof(struct dlm_lock_result_v5) + DLM_USER_LVB_LEN];
475 struct dlm_lock_result_v5 *result = (struct dlm_lock_result_v5 *)resultbuf;
476 char *fullresult = NULL;
477 int status;
478 void (*astaddr)(void *astarg);
479
480 status = read(fd, result, sizeof(resultbuf));
481 if (status <= 0)
482 return -1;
483
484 /* This shouldn't happen any more, can probably be removed */
485
486 if (result->length != status) {
487 int newstat;
488
489 fullresult = malloc(result->length);
490 if (!fullresult)
491 return -1;
492
493 newstat = read(fd, (struct dlm_lock_result_v5 *)fullresult,
494 result->length);
495
496 /* If it read OK then use the new data. otherwise we can
497 still deliver the AST, it just might not have all the
498 info in it...hmmm */
499
500 if (newstat == result->length)
501 result = (struct dlm_lock_result_v5 *)fullresult;
502 } else {
503 fullresult = resultbuf;
504 }
505
506
507 /* Copy lksb to user's buffer - except the LVB ptr */
508 memcpy(result->user_lksb, &result->lksb,
509 sizeof(struct dlm_lksb) - sizeof(char*));
510
511 /* Flip the status. Kernel space likes negative return codes,
512 userspace positive ones */
513 result->user_lksb->sb_status = -result->user_lksb->sb_status;
514
515 /* Copy optional items */
516 if (result->lvb_offset)
517 memcpy(result->user_lksb->sb_lvbptr,
518 fullresult + result->lvb_offset, DLM_LVB_LEN);
519
520 /* Call AST */
521 if (result->user_astaddr) {
522 astaddr = result->user_astaddr;
523 astaddr(result->user_astparam);
524 }
525
526 if (fullresult != resultbuf)
527 free(fullresult);
528
529 return 0;
530 }
531
532 static int do_dlm_dispatch_v6(int fd)
533 {
534 char resultbuf[sizeof(struct dlm_lock_result) + DLM_USER_LVB_LEN];
535 struct dlm_lock_result *result = (struct dlm_lock_result *)resultbuf;
536 int status;
537 void (*astaddr)(void *astarg);
538
539 status = read(fd, result, sizeof(resultbuf));
540 if (status <= 0)
541 return -1;
542
543 /* Copy lksb to user's buffer - except the LVB ptr */
544 memcpy(result->user_lksb, &result->lksb,
545 sizeof(struct dlm_lksb) - sizeof(char*));
546
547 /* Copy lvb to user's buffer */
548 if (result->lvb_offset)
549 memcpy(result->user_lksb->sb_lvbptr,
550 (char *)result + result->lvb_offset, DLM_LVB_LEN);
551
552 result->user_lksb->sb_status = -result->user_lksb->sb_status;
553
554 if (result->user_astaddr) {
555 astaddr = result->user_astaddr;
556 astaddr(result->user_astparam);
557 }
558
559 return 0;
560 }
561
562 static int do_dlm_dispatch(int fd)
563 {
564 if (kernel_version.version[0] == 5)
565 return do_dlm_dispatch_v5(fd);
566 else
567 return do_dlm_dispatch_v6(fd);
568 }
569
570
571 /*
572 * sync_write()
573 * Helper routine which supports the synchronous DLM calls. This
574 * writes a parameter block down to the DLM and waits for the
575 * operation to complete. This hides the different completion mechanism
576 * used when called from the main thread or the DLM 'AST' thread.
577 */
578
579 #ifdef _REENTRANT
580
581 static int sync_write_v5(struct dlm_ls_info *lsinfo,
582 struct dlm_write_request_v5 *req, int len)
583 {
584 struct lock_wait lwait;
585 int status;
586
587 if (pthread_self() == lsinfo->tid) {
588 /* This is the DLM worker thread, don't use lwait to sync */
589 req->i.lock.castaddr = dummy_ast_routine;
590 req->i.lock.castparam = NULL;
591
592 status = write(lsinfo->fd, req, len);
593 if (status < 0)
594 return -1;
595
596 while (req->i.lock.lksb->sb_status == EINPROG) {
597 do_dlm_dispatch_v5(lsinfo->fd);
598 }
599 } else {
600 pthread_cond_init(&lwait.cond, NULL);
601 pthread_mutex_init(&lwait.mutex, NULL);
602 pthread_mutex_lock(&lwait.mutex);
603
604 req->i.lock.castaddr = sync_ast_routine;
605 req->i.lock.castparam = &lwait;
606
607 status = write(lsinfo->fd, req, len);
608 if (status < 0)
609 return -1;
610
611 pthread_cond_wait(&lwait.cond, &lwait.mutex);
612 pthread_mutex_unlock(&lwait.mutex);
613 }
614
615 return status; /* lock status is in the lksb */
616 }
617
618 static int sync_write_v6(struct dlm_ls_info *lsinfo,
619 struct dlm_write_request *req, int len)
620 {
621 struct lock_wait lwait;
622 int status;
623
624 if (pthread_self() == lsinfo->tid) {
625 /* This is the DLM worker thread, don't use lwait to sync */
626 req->i.lock.castaddr = dummy_ast_routine;
627 req->i.lock.castparam = NULL;
628
629 status = write(lsinfo->fd, req, len);
630 if (status < 0)
631 return -1;
632
633 while (req->i.lock.lksb->sb_status == EINPROG) {
634 do_dlm_dispatch_v6(lsinfo->fd);
635 }
636 } else {
637 pthread_cond_init(&lwait.cond, NULL);
638 pthread_mutex_init(&lwait.mutex, NULL);
639 pthread_mutex_lock(&lwait.mutex);
640
641 req->i.lock.castaddr = sync_ast_routine;
642 req->i.lock.castparam = &lwait;
643
644 status = write(lsinfo->fd, req, len);
645 if (status < 0)
646 return -1;
647
648 pthread_cond_wait(&lwait.cond, &lwait.mutex);
649 pthread_mutex_unlock(&lwait.mutex);
650 }
651
652 return status; /* lock status is in the lksb */
653 }
654
655 #else /* _REENTRANT */
656
657 static int sync_write_v5(struct dlm_ls_info *lsinfo,
658 struct dlm_write_request_v5 *req, int len)
659 {
660 int status;
661
662 req->i.lock.castaddr = dummy_ast_routine;
663 req->i.lock.castparam = NULL;
664
665 status = write(lsinfo->fd, req, len);
666 if (status < 0)
667 return -1;
668
669 while (req->i.lock.lksb->sb_status == EINPROG) {
670 do_dlm_dispatch_v5(lsinfo->fd);
671 }
672
673 errno = req->i.lock.lksb->sb_status;
674 if (errno && errno != EUNLOCK)
675 return -1;
676 return 0;
677 }
678
679 static int sync_write_v6(struct dlm_ls_info *lsinfo,
680 struct dlm_write_request *req, int len)
681 {
682 int status;
683
684 req->i.lock.castaddr = dummy_ast_routine;
685 req->i.lock.castparam = NULL;
686
687 status = write(lsinfo->fd, req, len);
688 if (status < 0)
689 return -1;
690
691 while (req->i.lock.lksb->sb_status == EINPROG) {
692 do_dlm_dispatch_v6(lsinfo->fd);
693 }
694
695 errno = req->i.lock.lksb->sb_status;
696 if (errno && errno != EUNLOCK)
697 return -1;
698 return 0;
699 }
700
701 #endif /* _REENTRANT */
702
703
704 /*
705 * Lock
706 * All the ways to request/convert a lock
707 */
708
709 static int ls_lock_v5(dlm_lshandle_t ls,
710 uint32_t mode,
711 struct dlm_lksb *lksb,
712 uint32_t flags,
713 const void *name,
714 unsigned int namelen,
715 uint32_t parent,
716 void (*astaddr) (void *astarg),
717 void *astarg,
718 void (*bastaddr) (void *astarg))
719 {
720 char parambuf[sizeof(struct dlm_write_request_v5) + DLM_RESNAME_MAXLEN];
721 struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)parambuf;
722 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
723 int status;
724 int len;
725
726 memset(req, 0, sizeof(*req));
727 set_version_v5(req);
728
729 req->cmd = DLM_USER_LOCK;
730 req->i.lock.mode = mode;
731 req->i.lock.flags = (flags & ~LKF_WAIT);
732 req->i.lock.lkid = lksb->sb_lkid;
733 req->i.lock.parent = parent;
734 req->i.lock.lksb = lksb;
735 req->i.lock.castaddr = astaddr;
736 req->i.lock.bastaddr = bastaddr;
737 req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
738 req->i.lock.bastparam = astarg;
739
740 if (flags & LKF_CONVERT) {
741 req->i.lock.namelen = 0;
742 } else {
743 if (namelen > DLM_RESNAME_MAXLEN) {
744 errno = EINVAL;
745 return -1;
746 }
747 req->i.lock.namelen = namelen;
748 memcpy(req->i.lock.name, name, namelen);
749 }
750
751 if (flags & LKF_VALBLK) {
752 memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
753 }
754
755 len = sizeof(struct dlm_write_request_v5) + namelen;
756 lksb->sb_status = EINPROG;
757
758 if (flags & LKF_WAIT)
759 status = sync_write_v5(lsinfo, req, len);
760 else
761 status = write(lsinfo->fd, req, len);
762
763 if (status < 0)
764 return -1;
765
766 /*
767 * the lock id is the return value from the write on the device
768 */
769
770 if (status > 0)
771 lksb->sb_lkid = status;
772 return 0;
773 }
774
775 static int ls_lock_v6(dlm_lshandle_t ls,
776 uint32_t mode,
777 struct dlm_lksb *lksb,
778 uint32_t flags,
779 const void *name,
780 unsigned int namelen,
781 uint32_t parent,
782 void (*astaddr) (void *astarg),
783 void *astarg,
784 void (*bastaddr) (void *astarg),
785 uint64_t *xid,
786 uint64_t *timeout)
787 {
788 char parambuf[sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN];
789 struct dlm_write_request *req = (struct dlm_write_request *)parambuf;
790 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
791 int status;
792 int len;
793
794 memset(req, 0, sizeof(*req));
795 set_version_v6(req);
796
797 req->cmd = DLM_USER_LOCK;
798 req->i.lock.mode = mode;
799 req->i.lock.flags = (flags & ~LKF_WAIT);
800 req->i.lock.lkid = lksb->sb_lkid;
801 req->i.lock.parent = parent;
802 req->i.lock.lksb = lksb;
803 req->i.lock.castaddr = astaddr;
804 req->i.lock.bastaddr = bastaddr;
805 req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
806 req->i.lock.bastparam = astarg;
807
808 if (xid)
809 req->i.lock.xid = *xid;
810
811 if (flags & LKF_CONVERT) {
812 req->i.lock.namelen = 0;
813 } else {
814 if (namelen > DLM_RESNAME_MAXLEN) {
815 errno = EINVAL;
816 return -1;
817 }
818 req->i.lock.namelen = namelen;
819 memcpy(req->i.lock.name, name, namelen);
820 }
821
822 if (flags & LKF_VALBLK) {
823 memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
824 }
825
826 len = sizeof(struct dlm_write_request) + namelen;
827 lksb->sb_status = EINPROG;
828
829 if (flags & LKF_WAIT)
830 status = sync_write_v6(lsinfo, req, len);
831 else
832 status = write(lsinfo->fd, req, len);
833
834 if (status < 0)
835 return -1;
836
837 /*
838 * the lock id is the return value from the write on the device
839 */
840
841 if (status > 0)
842 lksb->sb_lkid = status;
843 return 0;
844 }
845
846 static int ls_lock(dlm_lshandle_t ls,
847 uint32_t mode,
848 struct dlm_lksb *lksb,
849 uint32_t flags,
850 const void *name,
851 unsigned int namelen,
852 uint32_t parent,
853 void (*astaddr) (void *astarg),
854 void *astarg,
855 void (*bastaddr) (void *astarg),
856 void *range)
857 {
858 /* no support for range locks */
859 if (range) {
860 errno = ENOSYS;
861 return -1;
862 }
863
864 if (flags & LKF_VALBLK && !lksb->sb_lvbptr) {
865 errno = EINVAL;
866 return -1;
867 }
868
869 if (kernel_version.version[0] == 5)
870 return ls_lock_v5(ls, mode, lksb, flags, name, namelen, parent,
871 astaddr, astarg, bastaddr);
872 else
873 return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
874 astaddr, astarg, bastaddr, NULL, NULL);
875 }
876
877 /*
878 * Extended async locking in own lockspace
879 */
880 int dlm_ls_lockx(dlm_lshandle_t ls,
881 uint32_t mode,
882 struct dlm_lksb *lksb,
883 uint32_t flags,
884 const void *name,
885 unsigned int namelen,
886 uint32_t parent,
887 void (*astaddr) (void *astarg),
888 void *astarg,
889 void (*bastaddr) (void *astarg),
890 uint64_t *xid,
891 uint64_t *timeout)
892 {
893 if (kernel_version.version[0] < 6) {
894 errno = ENOSYS;
895 return -1;
896 }
897
898 return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
899 astaddr, astarg, bastaddr, xid, timeout);
900 }
901
902 /*
903 * Async locking in own lockspace
904 */
905 int dlm_ls_lock(dlm_lshandle_t ls,
906 uint32_t mode,
907 struct dlm_lksb *lksb,
908 uint32_t flags,
909 const void *name,
910 unsigned int namelen,
911 uint32_t parent,
912 void (*astaddr) (void *astarg),
913 void *astarg,
914 void (*bastaddr) (void *astarg),
915 void *range)
916 {
917 return ls_lock(ls, mode, lksb, flags, name, namelen, parent,
918 astaddr, astarg, bastaddr, range);
919 }
920
921 /*
922 * Sync locking in own lockspace
923 */
924 int dlm_ls_lock_wait(dlm_lshandle_t ls,
925 uint32_t mode,
926 struct dlm_lksb *lksb,
927 uint32_t flags,
928 const void *name,
929 unsigned int namelen,
930 uint32_t parent,
931 void *bastarg,
932 void (*bastaddr) (void *bastarg),
933 void *range)
934 {
935 return ls_lock(ls, mode, lksb, flags | LKF_WAIT, name, namelen, parent,
936 NULL, bastarg, bastaddr, range);
937 }
938
939 /*
940 * Async locking in the default lockspace
941 */
942 int dlm_lock(uint32_t mode,
943 struct dlm_lksb *lksb,
944 uint32_t flags,
945 const void *name,
946 unsigned int namelen,
947 uint32_t parent,
948 void (*astaddr) (void *astarg),
949 void *astarg,
950 void (*bastaddr) (void *astarg),
951 void *range)
952 {
953 if (open_default_lockspace())
954 return -1;
955
956 return ls_lock(default_ls, mode, lksb, flags, name, namelen, parent,
957 astaddr, astarg, bastaddr, range);
958 }
959
960 /*
961 * Sync locking in the default lockspace
962 */
963 int dlm_lock_wait(uint32_t mode,
964 struct dlm_lksb *lksb,
965 uint32_t flags,
966 const void *name,
967 unsigned int namelen,
968 uint32_t parent,
969 void *bastarg,
970 void (*bastaddr) (void *bastarg),
971 void *range)
972 {
973 if (open_default_lockspace())
974 return -1;
975
976 return ls_lock(default_ls, mode, lksb, flags | LKF_WAIT, name, namelen,
977 parent, NULL, bastarg, bastaddr, range);
978 }
979
980
981 /*
982 * Unlock
983 * All the ways to unlock/cancel a lock
984 */
985
986 static int ls_unlock_v5(struct dlm_ls_info *lsinfo, uint32_t lkid,
987 uint32_t flags, struct dlm_lksb *lksb, void *astarg)
988 {
989 struct dlm_write_request_v5 req;
990
991 set_version_v5(&req);
992 req.cmd = DLM_USER_UNLOCK;
993 req.i.lock.lkid = lkid;
994 req.i.lock.flags = (flags & ~LKF_WAIT);
995 req.i.lock.lksb = lksb;
996 req.i.lock.castparam = astarg;
997 /* DLM_USER_UNLOCK will default to existing completion AST */
998 req.i.lock.castaddr = 0;
999 lksb->sb_status = EINPROG;
1000
1001 if (flags & LKF_WAIT)
1002 return sync_write_v5(lsinfo, &req, sizeof(req));
1003 else
1004 return write(lsinfo->fd, &req, sizeof(req));
1005 }
1006
1007 static int ls_unlock_v6(struct dlm_ls_info *lsinfo, uint32_t lkid,
1008 uint32_t flags, struct dlm_lksb *lksb, void *astarg)
1009 {
1010 struct dlm_write_request req;
1011
1012 set_version_v6(&req);
1013 req.cmd = DLM_USER_UNLOCK;
1014 req.i.lock.lkid = lkid;
1015 req.i.lock.flags = (flags & ~LKF_WAIT);
1016 req.i.lock.lksb = lksb;
1017 req.i.lock.namelen = 0;
1018 req.i.lock.castparam = astarg;
1019 /* DLM_USER_UNLOCK will default to existing completion AST */
1020 req.i.lock.castaddr = 0;
1021 lksb->sb_status = EINPROG;
1022
1023 if (flags & LKF_WAIT)
1024 return sync_write_v6(lsinfo, &req, sizeof(req));
1025 else
1026 return write(lsinfo->fd, &req, sizeof(req));
1027 }
1028
1029 int dlm_ls_unlock(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
1030 struct dlm_lksb *lksb, void *astarg)
1031 {
1032 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1033 int status;
1034
1035 if (ls == NULL) {
1036 errno = ENOTCONN;
1037 return -1;
1038 }
1039
1040 if (!lkid) {
1041 errno = EINVAL;
1042 return -1;
1043 }
1044
1045 if (kernel_version.version[0] == 5)
1046 status = ls_unlock_v5(lsinfo, lkid, flags, lksb, astarg);
1047 else
1048 status = ls_unlock_v6(lsinfo, lkid, flags, lksb, astarg);
1049
1050 if (status < 0)
1051 return -1;
1052 return 0;
1053 }
1054
1055 int dlm_ls_unlock_wait(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
1056 struct dlm_lksb *lksb)
1057 {
1058 return dlm_ls_unlock(ls, lkid, flags | LKF_WAIT, lksb, NULL);
1059 }
1060
1061 int dlm_unlock_wait(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb)
1062 {
1063 return dlm_ls_unlock_wait(default_ls, lkid, flags | LKF_WAIT, lksb);
1064 }
1065
1066 int dlm_unlock(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb,
1067 void *astarg)
1068 {
1069 return dlm_ls_unlock(default_ls, lkid, flags, lksb, astarg);
1070 }
1071
1072 int dlm_ls_deadlock_cancel(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags)
1073 {
1074 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1075 struct dlm_write_request req;
1076
1077 if (kernel_version.version[0] < 6) {
1078 errno = ENOSYS;
1079 return -1;
1080 }
1081
1082 if (ls == NULL) {
1083 errno = ENOTCONN;
1084 return -1;
1085 }
1086
1087 if (!lkid) {
1088 errno = EINVAL;
1089 return -1;
1090 }
1091
1092 set_version_v6(&req);
1093 req.cmd = DLM_USER_DEADLOCK;
1094 req.i.lock.lkid = lkid;
1095 req.i.lock.flags = flags;
1096
1097 return write(lsinfo->fd, &req, sizeof(req));
1098 }
1099
1100
1101 /*
1102 * Purge
1103 * Clear away orphan locks
1104 */
1105
1106 int dlm_ls_purge(dlm_lshandle_t ls, int nodeid, int pid)
1107 {
1108 struct dlm_write_request req;
1109 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1110 int status;
1111
1112 if (kernel_version.version[0] < 6) {
1113 errno = ENOSYS;
1114 return -1;
1115 }
1116
1117 if (ls == NULL) {
1118 errno = ENOTCONN;
1119 return -1;
1120 }
1121
1122 set_version_v6(&req);
1123 req.cmd = DLM_USER_PURGE;
1124 req.i.purge.nodeid = nodeid;
1125 req.i.purge.pid = pid;
1126
1127 status = write(lsinfo->fd, &req, sizeof(req));
1128
1129 if (status < 0)
1130 return -1;
1131 return 0;
1132 }
1133
1134
1135 /* These two routines for for users that want to
1136 * do their own fd handling.
1137 * This allows a non-threaded app to use the DLM.
1138 */
1139 int dlm_get_fd(void)
1140 {
1141 if (default_ls)
1142 {
1143 return default_ls->fd;
1144 }
1145 else
1146 {
1147 if (open_default_lockspace())
1148 return -1;
1149 else
1150 return default_ls->fd;
1151 }
1152 }
1153
1154 int dlm_dispatch(int fd)
1155 {
1156 int status;
1157 int fdflags;
1158
1159 fdflags = fcntl(fd, F_GETFL, 0);
1160 fcntl(fd, F_SETFL, fdflags | O_NONBLOCK);
1161 do
1162 {
1163 status = do_dlm_dispatch(fd);
1164 } while (status == 0);
1165
1166 /* EAGAIN is not an error */
1167 if (status < 0 && errno == EAGAIN)
1168 status = 0;
1169
1170 fcntl(fd, F_SETFL, fdflags);
1171 return status;
1172 }
1173
1174 /* Converts a lockspace handle into a file descriptor */
1175 int dlm_ls_get_fd(dlm_lshandle_t lockspace)
1176 {
1177 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)lockspace;
1178
1179 return lsinfo->fd;
1180 }
1181
1182 #ifdef _REENTRANT
1183 static void *dlm_recv_thread(void *lsinfo)
1184 {
1185 struct dlm_ls_info *lsi = lsinfo;
1186
1187 for (;;)
1188 do_dlm_dispatch(lsi->fd);
1189
1190 return NULL;
1191 }
1192
1193 /* Multi-threaded callers normally use this */
1194 int dlm_pthread_init(void)
1195 {
1196 if (open_default_lockspace())
1197 return -1;
1198
1199 if (default_ls->tid)
1200 {
1201 errno = EEXIST;
1202 return -1;
1203 }
1204
1205 if (pthread_create(&default_ls->tid, NULL, dlm_recv_thread, default_ls))
1206 {
1207 int saved_errno = errno;
1208 close(default_ls->fd);
1209 free(default_ls);
1210 default_ls = NULL;
1211 errno = saved_errno;
1212 return -1;
1213 }
1214 return 0;
1215 }
1216
1217 /* And same, for those with their own lockspace */
1218 int dlm_ls_pthread_init(dlm_lshandle_t ls)
1219 {
1220 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1221
1222 if (lsinfo->tid)
1223 {
1224 errno = EEXIST;
1225 return -1;
1226 }
1227
1228 return pthread_create(&lsinfo->tid, NULL, dlm_recv_thread, (void *)ls);
1229 }
1230 #endif
1231
1232 /*
1233 * Lockspace manipulation functions
1234 * Privileged users (checked by the kernel) can create/release lockspaces
1235 */
1236
1237 static int create_lockspace_v5(const char *name, uint32_t flags)
1238 {
1239 char reqbuf[sizeof(struct dlm_write_request_v5) + DLM_LOCKSPACE_LEN];
1240 struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)reqbuf;
1241 int namelen = strlen(name);
1242 int minor;
1243
1244 memset(reqbuf, 0, sizeof(reqbuf));
1245 set_version_v5(req);
1246
1247 req->cmd = DLM_USER_CREATE_LOCKSPACE;
1248 req->i.lspace.flags = flags;
1249
1250 if (namelen > DLM_LOCKSPACE_LEN) {
1251 errno = EINVAL;
1252 return -1;
1253 }
1254 memcpy(req->i.lspace.name, name, namelen);
1255
1256 minor = write(control_fd, req, sizeof(*req) + namelen);
1257
1258 return minor;
1259 }
1260
1261 static int create_lockspace_v6(const char *name, uint32_t flags)
1262 {
1263 char reqbuf[sizeof(struct dlm_write_request) + DLM_LOCKSPACE_LEN];
1264 struct dlm_write_request *req = (struct dlm_write_request *)reqbuf;
1265 int namelen = strlen(name);
1266 int minor;
1267
1268 memset(reqbuf, 0, sizeof(reqbuf));
1269 set_version_v6(req);
1270
1271 req->cmd = DLM_USER_CREATE_LOCKSPACE;
1272 req->i.lspace.flags = flags;
1273
1274 if (namelen > DLM_LOCKSPACE_LEN) {
1275 errno = EINVAL;
1276 return -1;
1277 }
1278 memcpy(req->i.lspace.name, name, namelen);
1279
1280 minor = write(control_fd, req, sizeof(*req) + namelen);
1281
1282 return minor;
1283 }
1284
1285 static dlm_lshandle_t create_lockspace(const char *name, mode_t mode,
1286 uint32_t flags)
1287 {
1288 char dev_path[PATH_MAX];
1289 char udev_path[PATH_MAX];
1290 struct dlm_ls_info *newls;
1291 int error, saved_errno, minor;
1292
1293 /* We use the control device for creating lockspaces. */
1294 if (open_control_device())
1295 return NULL;
1296
1297 newls = malloc(sizeof(struct dlm_ls_info));
1298 if (!newls)
1299 return NULL;
1300
1301 ls_dev_name(name, dev_path, sizeof(dev_path));
1302
1303 if (kernel_version.version[0] == 5)
1304 minor = create_lockspace_v5(name, flags);
1305 else
1306 minor = create_lockspace_v6(name, flags);
1307
1308 if (minor < 0)
1309 goto fail;
1310
1311 /* Wait for udev to create the device; the device it creates may
1312 have a truncated name due to the sysfs device name limit. */
1313
1314 error = find_udev_device(name, minor, udev_path);
1315 if (error)
1316 goto fail;
1317
1318 /* If the symlink already exists, find_udev_device() will return
1319 it and we'll skip this. */
1320
1321 if (strcmp(dev_path, udev_path)) {
1322 error = symlink(udev_path, dev_path);
1323 if (error)
1324 goto fail;
1325 }
1326
1327 /* Open it and return the struct as a handle */
1328
1329 newls->fd = open(dev_path, O_RDWR);
1330 if (newls->fd == -1)
1331 goto fail;
1332 if (mode)
1333 fchmod(newls->fd, mode);
1334 newls->tid = 0;
1335 fcntl(newls->fd, F_SETFD, 1);
1336 return (dlm_lshandle_t)newls;
1337
1338 fail:
1339 saved_errno = errno;
1340 free(newls);
1341 errno = saved_errno;
1342 return NULL;
1343 }
1344
1345 dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags)
1346 {
1347 flags &= ~DLM_LSFL_TIMEWARN;
1348 return create_lockspace(name, mode, flags);
1349 }
1350
1351 dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode)
1352 {
1353 return create_lockspace(name, mode, 0);
1354 }
1355
1356 static int release_lockspace_v5(uint32_t minor, uint32_t flags)
1357 {
1358 struct dlm_write_request_v5 req;
1359
1360 set_version_v5(&req);
1361 req.cmd = DLM_USER_REMOVE_LOCKSPACE;
1362 req.i.lspace.minor = minor;
1363 req.i.lspace.flags = flags;
1364
1365 return write(control_fd, &req, sizeof(req));
1366 }
1367
1368 static int release_lockspace_v6(uint32_t minor, uint32_t flags)
1369 {
|
(1) Event var_decl: |
Declaring variable "req" without initializer. |
| Also see events: |
[uninit_use_in_call] |
1370 struct dlm_write_request req;
1371
1372 set_version_v6(&req);
1373 req.cmd = DLM_USER_REMOVE_LOCKSPACE;
1374 req.i.lspace.minor = minor;
1375 req.i.lspace.flags = flags;
1376
|
(2) Event uninit_use_in_call: |
Using uninitialized value "req". Field "req.unused" is uninitialized when calling "write". |
| Also see events: |
[var_decl] |
1377 return write(control_fd, &req, sizeof(req));
1378 }
1379
1380 static int release_lockspace(uint32_t minor, uint32_t flags)
1381 {
1382 if (kernel_version.version[0] == 5)
1383 return release_lockspace_v5(minor, flags);
1384 else
1385 return release_lockspace_v6(minor, flags);
1386 }
1387
1388 int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force)
1389 {
1390 char dev_path[PATH_MAX];
1391 struct stat st;
1392 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1393 uint32_t flags = 0;
1394 int fd, is_symlink = 0;
1395
1396 ls_dev_name(name, dev_path, sizeof(dev_path));
1397 if (!lstat(dev_path, &st) && S_ISLNK(st.st_mode))
1398 is_symlink = 1;
1399
1400 /* We need the minor number */
1401 if (fstat(lsinfo->fd, &st))
1402 return -1;
1403
1404 /* Close the lockspace first if it's in use */
1405 ls_pthread_cleanup(lsinfo);
1406
1407 if (open_control_device())
1408 return -1;
1409
1410 if (force)
1411 flags = DLM_USER_LSFLG_FORCEFREE;
1412
1413 release_lockspace(minor(st.st_rdev), flags);
1414
1415 if (!is_symlink)
1416 return 0;
1417
1418 /* The following open is used to detect if our release was the last.
1419 It will fail if our release was the last, because either:
1420 . udev has already removed the truncated sysfs device name (ENOENT)
1421 . the misc device has been deregistered in the kernel (ENODEV)
1422 (the deregister completes before release returns)
1423
1424 So, if the open fails, we know that our release was the last,
1425 udev will be removing the device with the truncated name (if it
1426 hasn't already), and we should remove the symlink. */
1427
1428 fd = open(dev_path, O_RDWR);
1429 if (fd < 0)
1430 unlink(dev_path);
1431 else
1432 close(fd); /* our release was not the last */
1433
1434 return 0;
1435 }
1436
1437 /*
1438 * Normal users just open/close lockspaces
1439 */
1440
1441 dlm_lshandle_t dlm_open_lockspace(const char *name)
1442 {
1443 char dev_name[PATH_MAX];
1444 struct dlm_ls_info *newls;
1445 int saved_errno;
1446
1447 /* Need to detect kernel version */
1448 if (open_control_device())
1449 return NULL;
1450
1451 newls = malloc(sizeof(struct dlm_ls_info));
1452 if (!newls)
1453 return NULL;
1454
1455 newls->tid = 0;
1456 ls_dev_name(name, dev_name, sizeof(dev_name));
1457
1458 newls->fd = open(dev_name, O_RDWR);
1459 saved_errno = errno;
1460
1461 if (newls->fd == -1) {
1462 free(newls);
1463 errno = saved_errno;
1464 return NULL;
1465 }
1466 fcntl(newls->fd, F_SETFD, 1);
1467 return (dlm_lshandle_t)newls;
1468 }
1469
1470 int dlm_close_lockspace(dlm_lshandle_t ls)
1471 {
1472 struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
1473
1474 ls_pthread_cleanup(lsinfo);
1475 return 0;
1476 }
1477
1478 int dlm_kernel_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
1479 {
1480 if (open_control_device())
1481 return -1;
1482 *major = kernel_version.version[0];
1483 *minor = kernel_version.version[1];
1484 *patch = kernel_version.version[2];
1485 return 0;
1486 }
1487
1488 void dlm_library_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
1489 {
1490 *major = DLM_DEVICE_VERSION_MAJOR;
1491 *minor = DLM_DEVICE_VERSION_MINOR;
1492 *patch = DLM_DEVICE_VERSION_PATCH;
1493 }
1494
1495