[Ocfs2-tools-commits] mfasheh commits r577 - in trunk: . libo2dlm libo2dlm/include

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Tue Jan 25 15:57:24 CST 2005


Author: mfasheh
Date: 2005-01-25 15:57:22 -0600 (Tue, 25 Jan 2005)
New Revision: 577

Added:
   trunk/libo2dlm/
   trunk/libo2dlm/Makefile
   trunk/libo2dlm/include/
   trunk/libo2dlm/include/kernel-list.h
   trunk/libo2dlm/include/o2dlm.h
   trunk/libo2dlm/o2dlm.c
   trunk/libo2dlm/o2dlm_err.et.in
Modified:
   trunk/Makefile
   trunk/configure.in
Log:
* commit libo2dlm, a small userspace library to facilitate communication
  with ocfs2_dlmfs. This needs testing.



Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/Makefile	2005-01-25 21:57:22 UTC (rev 577)
@@ -22,7 +22,7 @@
 $(error could not detect architecture for tools)
 endif
 
-SUBDIRS = libocfs2 libo2cb fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 clusterbo mount.ocfs2 listuuid sizetest extras patches
+SUBDIRS = libocfs2 libo2cb libo2dlm fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 clusterbo mount.ocfs2 listuuid sizetest extras patches
 
 ifdef BUILD_OCFS2CDSL
 SUBDIRS += ocfs2cdsl

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/configure.in	2005-01-25 21:57:22 UTC (rev 577)
@@ -193,6 +193,7 @@
 Config.make
 libocfs2/ocfs2_err.et
 libo2cb/o2cb_err.et
+libo2dlm/o2dlm_err.et
 debugfs.ocfs2/debugfs.ocfs2.8
 mkfs.ocfs2/mkfs.ocfs2.8
 fsck.ocfs2/fsck.ocfs2.8

Added: trunk/libo2dlm/Makefile
===================================================================
--- trunk/libo2dlm/Makefile	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/libo2dlm/Makefile	2005-01-25 21:57:22 UTC (rev 577)
@@ -0,0 +1,77 @@
+TOPDIR = ..
+
+include $(TOPDIR)/Preamble.make
+
+WARNINGS = -Wall -Wstrict-prototypes -Wmissing-prototypes \
+	-Wmissing-declarations
+
+ifdef OCFS_DEBUG
+OPTS += -ggdb
+else
+OPTS += -O2
+endif
+
+INCLUDES = -Iinclude
+
+LIBRARIES = libo2dlm.a
+
+CFLAGS = $(OPTS) $(WARNINGS) -fPIC
+CPPFLAGS += -DO2DLM_FLAT_INCLUDES
+
+ifneq ($(OCFS2_DEBUG_EXE),)
+DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES))
+DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES)))
+
+.SECONDARY:
+
+UNINST_PROGRAMS += $(DEBUG_EXE_PROGRAMS)
+
+debug_%.o : %.c 
+	$(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(LOCAL_CPPFLAGS) \
+		$(INCLUDES) $(DEFINES) \
+		-DDEBUG_EXE -o $@ -c $<
+
+debug_%: debug_%.o libo2dlm.a
+	$(LINK) $(COM_ERR_LIBS)
+
+endif
+
+CFILES = o2dlm.c
+
+HFILES = include/o2dlm.h
+
+HFILES_GEN =		\
+	include/o2dlm_err.h
+
+$(CFILES): $(HFILES_GEN)
+
+OBJS = $(subst .c,.o,$(CFILES)) \
+	o2dlm_err.o
+
+o2dlm_err.et: o2dlm_err.et.in
+	cd $(TOPDIR) && ./config.status
+
+include/o2dlm_err.h: o2dlm_err.h
+	cp $< $@
+
+o2dlm_err.c o2dlm_err.h: o2dlm_err.et
+	compile_et o2dlm_err.et
+
+libo2dlm.a: $(OBJS)
+	rm -f $@
+	$(AR) r $@ $^
+	$(RANLIB) $@
+
+DIST_FILES = $(CFILES) $(HFILES) o2dlm_err.et.in
+
+DIST_RULES = dist-subdircreate
+
+dist-subdircreate:
+	$(TOPDIR)/mkinstalldirs $(DIST_DIR)/include
+
+CLEAN_RULES = clean-err
+
+clean-err:
+	rm -f o2dlm_err.c o2dlm_err.h include/o2dlm_err.h
+
+include $(TOPDIR)/Postamble.make

Added: trunk/libo2dlm/include/kernel-list.h
===================================================================
--- trunk/libo2dlm/include/kernel-list.h	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/libo2dlm/include/kernel-list.h	2005-01-25 21:57:22 UTC (rev 577)
@@ -0,0 +1,116 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#if (!defined(__GNUC__) && !defined(__WATCOMC__))
+#define __inline__
+#endif
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/*
+ * Insert a new entry after the specified head..
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/*
+ * Insert a new entry at the tail
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static __inline__ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Splice in "list" into "head"
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each(pos, head) \
+        for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_safe(pos, n, head) \
+	        for (pos = (head)->next, n = pos->next; pos != (head); \
+		                     pos = n, n = pos->next)
+
+#endif

Added: trunk/libo2dlm/include/o2dlm.h
===================================================================
--- trunk/libo2dlm/include/o2dlm.h	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/libo2dlm/include/o2dlm.h	2005-01-25 21:57:22 UTC (rev 577)
@@ -0,0 +1,105 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * o2dlm.h
+ *
+ * Defines the userspace locking api
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2,  as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef _O2DLM_H_
+#define _O2DLM_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <kernel-list.h>
+
+#include <et/com_err.h>
+
+#if O2DLM_FLAT_INCLUDES
+#include "o2dlm_err.h"
+#else
+#include <o2dlm/o2dlm_err.h>
+#endif
+
+#define O2DLM_LOCK_ID_MAX_LEN       32
+#define O2DLM_DOMAIN_MAX_LEN        255
+
+/* + null pointer */
+#define O2DLM_MAX_FULL_DOMAIN_PATH (PATH_MAX + 1)
+
+/* valid lock flags */
+#define O2DLM_TRYLOCK      0x01
+#define O2DLM_VALID_FLAGS  (O2DLM_TRYLOCK)
+
+/* valid lock levels */
+enum o2dlm_lock_level
+{
+	O2DLM_LEVEL_PRMODE,
+	O2DLM_LEVEL_EXMODE
+};
+
+struct o2dlm_lock_res
+{
+	struct list_head      l_list;  /* to hang us off the locks list */
+	char                  l_id[O2DLM_LOCK_ID_MAX_LEN]; /* 32 byte,
+							    * null
+							    * terminated
+							    * string */
+	int                   l_flags; /* limited set of flags */
+	enum o2dlm_lock_level l_level; /* either PR or EX */
+	int                   l_fd;    /* the fd returned by the open call */
+};
+
+struct o2dlm_ctxt
+{
+	struct list_head ct_locks;  /* the list of locks */
+	char             ct_domain_path[O2DLM_MAX_FULL_DOMAIN_PATH]; /* domain
+								      * dir */
+	char             ct_ctxt_lock_name[O2DLM_LOCK_ID_MAX_LEN];
+};
+
+/* Expects to be given a path to the root of a valid ocfs2_dlmfs file
+ * system and a domain identifier of length <= 255 characters including
+ * the '\0' */
+errcode_t o2dlm_initialize(const char *dlmfs_path,
+			   const char *domain_name,
+			   struct o2dlm_ctxt **ctxt);
+
+/*
+ * lock_name, is a valid lock name -- 32 bytes long including the null
+ * character
+ *
+ * Returns: 0 if we got the lock we wanted
+ */
+errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt,
+		     const char *lockid,
+		     int flags,
+		     enum o2dlm_lock_level level);
+
+/* returns 0 on success */
+errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt,
+		       char *lockid);
+
+/*
+ * Unlocks all pending locks and frees the lock context.
+ */
+errcode_t o2dlm_destroy(struct o2dlm_ctxt *ctxt);
+#endif /* _O2DLM_H_ */

Added: trunk/libo2dlm/o2dlm.c
===================================================================
--- trunk/libo2dlm/o2dlm.c	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/libo2dlm/o2dlm.c	2005-01-25 21:57:22 UTC (rev 577)
@@ -0,0 +1,494 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * o2dlm.c
+ *
+ * Defines the userspace locking api
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2,  as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <sys/statfs.h>
+#include <string.h>
+
+#include <kernel-list.h>
+
+#include <o2dlm.h>
+
+#define USER_DLMFS_MAGIC	0x76a9f425
+
+static errcode_t o2dlm_generate_random_value(int64_t *value)
+{
+	int randfd = 0;
+	int readlen = sizeof(*value);
+
+	if ((randfd = open("/dev/urandom", O_RDONLY)) == -1)
+		return O2DLM_ET_RANDOM;
+
+	if (read(randfd, value, readlen) != readlen)
+		return O2DLM_ET_RANDOM;
+
+	close(randfd);
+
+	return 0;
+}
+
+static errcode_t o2dlm_alloc_ctxt(const char *mnt_path,
+				  const char *dirname,
+				  struct o2dlm_ctxt **dlm_ctxt)
+{
+	errcode_t err;
+	struct o2dlm_ctxt *ctxt;
+	int64_t rand;
+	int len;
+
+	err = o2dlm_generate_random_value(&rand);
+	if (err)
+		return err;
+
+	ctxt = malloc(sizeof(*ctxt));
+	if (!ctxt)
+		return O2DLM_ET_NO_MEMORY;
+
+	len = snprintf(ctxt->ct_ctxt_lock_name, O2DLM_LOCK_ID_MAX_LEN,
+		       ".%016"PRIx64, rand);
+	if (len == O2DLM_LOCK_ID_MAX_LEN) {
+		err = O2DLM_ET_NAME_TOO_LONG;
+		goto exit_and_free;
+	} else if (len < 0) {
+		err = O2DLM_ET_OUTPUT_ERROR;
+		goto exit_and_free;
+	}
+
+	INIT_LIST_HEAD(&ctxt->ct_locks);
+
+	len = snprintf(ctxt->ct_domain_path, PATH_MAX + 1, "%s/%s",
+		       mnt_path, dirname);
+	if (len == (PATH_MAX + 1)) {
+		err = O2DLM_ET_BAD_DOMAIN_DIR;
+		goto exit_and_free;
+	} else if (len < 0) {
+		err = O2DLM_ET_OUTPUT_ERROR;
+		goto exit_and_free;
+	}
+
+	*dlm_ctxt = ctxt;
+	err = 0;
+exit_and_free:
+	if (err)
+		free(ctxt);
+	return err;
+}
+
+static void o2dlm_free_ctxt(struct o2dlm_ctxt *ctxt)
+{
+	free(ctxt);
+}
+
+static errcode_t o2dlm_check_user_dlmfs(const char *dlmfs_path)
+{
+	struct statfs stat;
+	int ret;
+
+	ret = statfs(dlmfs_path, &stat);
+	if (ret)
+		return O2DLM_ET_STATFS;
+
+	if (stat.f_type != USER_DLMFS_MAGIC)
+		return O2DLM_ET_NO_FS;
+
+	return 0;
+}
+
+static errcode_t o2dlm_check_domain_dir(struct o2dlm_ctxt *ctxt)
+{
+	int status;
+	char *dirpath = ctxt->ct_domain_path;
+	struct stat st;
+
+	status = stat(dirpath, &st);
+	if (status) {
+		if (errno == ENOENT)
+			return O2DLM_ET_NO_DOMAIN_DIR;
+		return O2DLM_ET_BAD_DOMAIN_DIR;
+	}
+
+	if (!S_ISDIR(st.st_mode))
+		return O2DLM_ET_BAD_DOMAIN_DIR;
+
+	return 0;
+}
+
+#define O2DLM_DOMAIN_DIR_MODE 0755
+
+static errcode_t o2dlm_create_domain(struct o2dlm_ctxt *ctxt)
+{
+	int status;
+	char *dirpath = ctxt->ct_domain_path;
+
+	status = mkdir(dirpath, O2DLM_DOMAIN_DIR_MODE);
+	if (status)
+		return O2DLM_ET_DOMAIN_CREATE;
+	return 0;
+}
+
+static errcode_t o2dlm_delete_domain_dir(struct o2dlm_ctxt *ctxt)
+{
+	int ret;
+
+	ret = rmdir(ctxt->ct_domain_path);
+	if (ret) {
+		if (errno == ENOTEMPTY)
+			return O2DLM_ET_BUSY_DOMAIN_DIR;
+		return O2DLM_ET_DOMAIN_DESTROY;
+	}
+	return 0;
+}
+
+errcode_t o2dlm_initialize(const char *dlmfs_path,
+			   const char *domain_name,
+			   struct o2dlm_ctxt **dlm_ctxt)
+{
+	errcode_t ret, dir_created = 0;
+	struct o2dlm_ctxt *ctxt;
+
+	if (strlen(domain_name) >= O2DLM_DOMAIN_MAX_LEN)
+		return O2DLM_ET_NAME_TOO_LONG;
+
+	if ((strlen(dlmfs_path) + strlen(domain_name)) >
+	    O2DLM_MAX_FULL_DOMAIN_PATH)
+		return O2DLM_ET_NAME_TOO_LONG;
+
+	ret = o2dlm_check_user_dlmfs(dlmfs_path);
+	if (ret)
+		return ret;
+
+	ret = o2dlm_alloc_ctxt(dlmfs_path, domain_name, &ctxt);
+	if (ret)
+		return ret;
+
+	ret = o2dlm_check_domain_dir(ctxt);
+	if (ret) {
+		if (ret != O2DLM_ET_NO_DOMAIN_DIR) {
+			o2dlm_free_ctxt(ctxt);
+			return ret;
+		}
+
+		/* the domain does not yet exist - create it ourselves. */
+		ret = o2dlm_create_domain(ctxt);
+		if (ret) {
+			o2dlm_free_ctxt(ctxt);
+			return ret;
+		}
+		dir_created = 1;
+	}
+
+	/* What we want to do here is create a lock which we'll hold
+	 * open for the duration of this context. This way if another
+	 * process won't be able to shut down this domain underneath
+	 * us. */
+	ret = o2dlm_lock(ctxt, ctxt->ct_ctxt_lock_name, 0, O2DLM_LEVEL_PRMODE);
+	if (ret) {
+		if (dir_created)
+			o2dlm_delete_domain_dir(ctxt); /* best effort
+							* cleanup. */
+		o2dlm_free_ctxt(ctxt);
+		return ret;
+	}
+
+	*dlm_ctxt = ctxt;
+	return 0;
+}
+
+static errcode_t o2dlm_full_path(char *path,
+				 struct o2dlm_ctxt *ctxt,
+				 const char *filename)
+{
+	int ret;
+	int len = PATH_MAX + 1;
+
+	ret = snprintf(path, len, "%s/%s", ctxt->ct_domain_path, filename);
+	if (ret == len)
+		return O2DLM_ET_NAME_TOO_LONG;
+	else if (ret < 0)
+		return O2DLM_ET_OUTPUT_ERROR;
+	return 0;
+}
+
+static struct o2dlm_lock_res *o2dlm_find_lock_res(struct o2dlm_ctxt *ctxt,
+						  const char *lockid)
+{
+	struct o2dlm_lock_res *lockres = NULL;
+	struct list_head *p;
+
+	list_for_each(p, &ctxt->ct_locks) {
+		lockres = list_entry(p, struct o2dlm_lock_res, l_list);
+		if (!strcmp(lockid, lockres->l_id))
+			break;
+	}
+	return lockres;
+}
+
+static int o2dlm_translate_lock_flags(enum o2dlm_lock_level level,
+				      int lockflags)
+{
+	int flags;
+
+	switch (level) {
+	case O2DLM_LEVEL_PRMODE:
+		flags = O_RDONLY;
+		break;
+	case O2DLM_LEVEL_EXMODE:
+		flags = O_WRONLY;
+		break;
+	default:
+		flags = 0;
+	}
+
+	if (lockflags & O2DLM_TRYLOCK)
+		flags |= O_NONBLOCK;
+
+	return flags;
+}
+
+static struct o2dlm_lock_res *o2dlm_new_lock_res(const char *id,
+						 enum o2dlm_lock_level level,
+						 int flags)
+{
+	struct o2dlm_lock_res *lockres;
+
+	lockres = malloc(sizeof(*lockres));
+	if (lockres) {
+		memset(lockres, 0, sizeof(*lockres));
+
+		INIT_LIST_HEAD(&lockres->l_list);
+
+		strncpy(lockres->l_id, id, O2DLM_LOCK_ID_MAX_LEN);
+
+		lockres->l_flags = flags;
+		lockres->l_level = level;
+		lockres->l_fd    = -1;
+	}
+	return lockres;
+}
+
+#define O2DLM_OPEN_MODE         0664
+
+errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt,
+		     const char *lockid,
+		     int lockflags,
+		     enum o2dlm_lock_level level)
+{
+	int ret, flags, fd;
+	char *path;
+	struct o2dlm_lock_res *lockres;
+
+	/* names starting with '.' are reserved. */
+	if (lockid[0] == '.')
+		return O2DLM_ET_INVALID_LOCK_NAME;
+
+	if (strlen(lockid) >= O2DLM_LOCK_ID_MAX_LEN)
+		return O2DLM_ET_INVALID_LOCK_NAME;
+
+	if (level != O2DLM_LEVEL_PRMODE && level != O2DLM_LEVEL_EXMODE)
+		return O2DLM_ET_INVALID_LOCK_LEVEL;
+
+	lockres = o2dlm_find_lock_res(ctxt, lockid);
+	if (lockres)
+		return O2DLM_ET_RECURSIVE_LOCK;
+
+	path = malloc(PATH_MAX + 1);
+	if (!path)
+		return O2DLM_ET_NO_MEMORY;
+
+	ret = o2dlm_full_path(path, ctxt, lockid);
+	if (ret) {
+		free(path);
+		return ret;
+	}
+
+	lockflags &= O2DLM_VALID_FLAGS;
+	flags = o2dlm_translate_lock_flags(level, lockflags);
+
+	lockres = o2dlm_new_lock_res(lockid, level, flags);
+	if (!lockres) {
+		free(path);
+		return O2DLM_ET_NO_MEMORY;
+	}
+
+	fd = open(path, flags|O_CREAT, O2DLM_OPEN_MODE);
+	if (fd < 0) {
+		free(path);
+		free(lockres);
+		return O2DLM_ET_LOCKING;
+	}
+
+	lockres->l_flags = lockflags;
+	lockres->l_fd = fd;
+
+	list_add_tail(&lockres->l_list, &ctxt->ct_locks);
+
+	free(path);
+
+	return 0;
+}
+
+static errcode_t o2dlm_unlock_lock_res(struct o2dlm_ctxt *ctxt,
+				      struct o2dlm_lock_res *lockres)
+{
+	int ret, len = PATH_MAX + 1;
+	char *path;
+
+	/* This does the actual unlock. */
+	close(lockres->l_fd);
+
+	/* From here on down, we're trying to unlink the lockres file
+	 * from the dlm file system. Note that EBUSY from unlink is
+	 * not a fatal error here -- it simply means that the lock is
+	 * in use by some other process. */
+	path = malloc(len);
+	if (!path)
+		return O2DLM_ET_NO_MEMORY;
+
+	ret = o2dlm_full_path(path, ctxt, lockres->l_id);
+	if (ret) {
+		free(path);
+		return ret;
+	}
+
+	ret = unlink(path);
+	free (path);
+	if (ret) {
+		if (errno == EBUSY)
+			return O2DLM_ET_BUSY_LOCK;
+		return O2DLM_ET_UNLINK;
+	}
+	return 0;
+}
+
+errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt,
+		       char *lockid)
+{
+	int ret;
+	struct o2dlm_lock_res *lockres = NULL;
+
+	lockres = o2dlm_find_lock_res(ctxt, lockid);
+	if (!lockres)
+		return O2DLM_ET_UNKNOWN_LOCK;
+
+	list_del(&lockres->l_list);
+
+	ret = o2dlm_unlock_lock_res(ctxt, lockres);
+
+	free(lockres);
+
+	if (ret && (ret != O2DLM_ET_BUSY_LOCK))
+		return ret;
+	return 0;
+}
+
+static errcode_t o2dlm_unlink_all(struct o2dlm_ctxt *ctxt)
+{
+	int ret;
+	char *name;
+        DIR *dir;
+        struct dirent *de;
+
+	name = malloc(PATH_MAX + 1);
+	if (!name)
+		return O2DLM_ET_NO_MEMORY;
+
+	dir = opendir(ctxt->ct_domain_path);
+	if (!dir) {
+		free(name);
+		return O2DLM_ET_DOMAIN_DIR;
+	}
+
+	de = readdir(dir);
+	while(de) {
+		if ((strlen(de->d_name) == 1) &&
+		    (de->d_name[0] == '.'))
+			continue;
+		if ((strlen(de->d_name) == 2) &&
+		    (de->d_name[0] == '.') &&
+		    (de->d_name[1] == '.'))
+			continue;
+
+		ret = o2dlm_full_path(name, ctxt, de->d_name);
+		if (ret)
+			goto close_and_free;
+
+		ret = unlink(name);
+		if (ret) {
+			if (errno != EBUSY) {
+				ret = O2DLM_ET_UNLINK;
+				goto close_and_free;
+			}
+		}
+		de = readdir(dir);
+	}
+
+	ret = 0;
+close_and_free:
+	closedir(dir);
+	free(name);
+	return ret;
+}
+
+errcode_t o2dlm_destroy(struct o2dlm_ctxt *ctxt)
+{
+	int ret;
+	int error = 0;
+	struct o2dlm_lock_res *lockres;
+        struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &ctxt->ct_locks) {
+		lockres = list_entry(p, struct o2dlm_lock_res, l_list);
+		list_del(&lockres->l_list);
+
+		ret = o2dlm_unlock_lock_res(ctxt, lockres);
+		if (ret && (ret != O2DLM_ET_BUSY_LOCK))
+			error = O2DLM_ET_FAILED_UNLOCKS;
+		free(lockres);
+	}
+	if (error)
+		goto free_and_exit;
+
+	ret = o2dlm_unlink_all(ctxt);
+	if (ret && ret != O2DLM_ET_BUSY_LOCK) {
+		error = ret;
+		goto free_and_exit;
+	}
+
+	ret = o2dlm_delete_domain_dir(ctxt);
+	if (ret && ret != O2DLM_ET_BUSY_DOMAIN_DIR)
+		error = ret;
+
+free_and_exit:
+	o2dlm_free_ctxt(ctxt);
+	return error;
+}

Added: trunk/libo2dlm/o2dlm_err.et.in
===================================================================
--- trunk/libo2dlm/o2dlm_err.et.in	2005-01-25 21:51:12 UTC (rev 576)
+++ trunk/libo2dlm/o2dlm_err.et.in	2005-01-25 21:57:22 UTC (rev 577)
@@ -0,0 +1,93 @@
+#
+# o2dlm_err.et.in
+#
+# Error codes for the O2DLM library.
+#
+# Copyright (C) 2005 Oracle.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License, version 2,  as published by the Free Software Foundation.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 021110-1307, USA.
+#
+	error_table o2dl
+
+ec	O2DLM_ET_BASE,
+	"O2DLM Library version @VERSION@"
+
+ec	O2DLM_ET_NO_MEMORY,
+	"Memory allocation failed"
+
+ec	O2DLM_ET_SERVICE_UNAVAILABLE,
+	"Unable to access cluster service"
+
+ec	O2DLM_ET_INVALID_LOCK_NAME,
+	"Invalid name for a lock"
+
+ec	O2DLM_ET_INVALID_LOCK_LEVEL,
+	"Invalid locking level"
+
+ec	O2DLM_ET_INTERNAL_FAILURE,
+	"Internal logic failure"
+
+ec	O2DLM_ET_NAME_TOO_LONG,
+	"Name too long"
+
+ec	O2DLM_ET_STATFS,
+	"Could not stat user_dlmfs mountpoint"
+
+ec	O2DLM_ET_NO_FS,
+	"ocfs2_dlmfs file system was not found"
+
+ec	O2DLM_ET_NO_DOMAIN_DIR,
+	"No directory for domain was found"
+
+ec	O2DLM_ET_BAD_DOMAIN_DIR,
+	"Could not stat domain directory"
+
+ec	O2DLM_ET_BUSY_DOMAIN_DIR,
+	"Domain directory has active locks"
+
+ec	O2DLM_ET_DOMAIN_DIR,
+	"Could not read domain dir"
+
+ec	O2DLM_ET_DOMAIN_DESTROY,
+	"Could not destroy domain"
+
+ec	O2DLM_ET_DOMAIN_CREATE,
+	"Could not create domain"
+
+ec	O2DLM_ET_RANDOM,
+	"Could not generate random value"
+
+ec	O2DLM_ET_BUSY_LOCK,
+	"Lock resource is in use by another process"
+
+ec	O2DLM_ET_OUTPUT_ERROR,
+	"Output Error"
+
+ec	O2DLM_ET_UNLINK,
+	"Error unlinking lock resource"
+
+ec	O2DLM_ET_UNKNOWN_LOCK,
+	"Could not find lock resource"
+
+ec	O2DLM_ET_RECURSIVE_LOCK,
+	"Already have a lock on this resource"
+
+ec	O2DLM_ET_LOCKING,
+	"Could not take lock"
+
+ec	O2DLM_ET_FAILED_UNLOCKS,
+	"Could not drop all locks"
+
+	end



More information about the Ocfs2-tools-commits mailing list