mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
[DLM] The core of the DLM for GFS2/CLVM
This is the core of the distributed lock manager which is required to use GFS2 as a cluster filesystem. It is also used by CLVM and can be used as a standalone lock manager independantly of either of these two projects. It implements VAX-style locking modes. Signed-off-by: David Teigland <teigland@redhat.com> Signed-off-by: Steve Whitehouse <swhiteho@redhat.com>
This commit is contained in:
committed by
Steven Whitehouse
parent
e473142070
commit
e7fd41792f
@@ -1831,6 +1831,7 @@ source "fs/partitions/Kconfig"
|
||||
endmenu
|
||||
|
||||
source "fs/nls/Kconfig"
|
||||
source "fs/dlm/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ obj-$(CONFIG_SYSFS) += sysfs/
|
||||
obj-y += devpts/
|
||||
|
||||
obj-$(CONFIG_PROFILING) += dcookies.o
|
||||
obj-$(CONFIG_DLM) += dlm/
|
||||
|
||||
# Do not add any filesystems before this line
|
||||
obj-$(CONFIG_REISERFS_FS) += reiserfs/
|
||||
|
||||
30
fs/dlm/Kconfig
Normal file
30
fs/dlm/Kconfig
Normal file
@@ -0,0 +1,30 @@
|
||||
menu "Distributed Lock Manager"
|
||||
depends on INET && EXPERIMENTAL
|
||||
|
||||
config DLM
|
||||
tristate "Distributed Lock Manager (DLM)"
|
||||
depends on SYSFS
|
||||
depends on IPV6 || IPV6=n
|
||||
select IP_SCTP
|
||||
select CONFIGFS_FS
|
||||
help
|
||||
A general purpose distributed lock manager for kernel or userspace
|
||||
applications.
|
||||
|
||||
config DLM_DEVICE
|
||||
tristate "DLM device for userspace access"
|
||||
depends on DLM
|
||||
help
|
||||
This module creates a misc device through which the dlm lockspace
|
||||
and locking functions become available to userspace applications
|
||||
(usually through the libdlm library).
|
||||
|
||||
config DLM_DEBUG
|
||||
bool "DLM debugging"
|
||||
depends on DLM
|
||||
help
|
||||
Under the debugfs mount point, the name of each lockspace will
|
||||
appear as a file in the "dlm" directory. The output is the
|
||||
list of resource and locks the local node knows about.
|
||||
|
||||
endmenu
|
||||
21
fs/dlm/Makefile
Normal file
21
fs/dlm/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
obj-$(CONFIG_DLM) += dlm.o
|
||||
obj-$(CONFIG_DLM_DEVICE) += dlm_device.o
|
||||
|
||||
dlm-y := ast.o \
|
||||
config.o \
|
||||
dir.o \
|
||||
lock.o \
|
||||
lockspace.o \
|
||||
lowcomms.o \
|
||||
main.o \
|
||||
member.o \
|
||||
memory.o \
|
||||
midcomms.o \
|
||||
rcom.o \
|
||||
recover.o \
|
||||
recoverd.o \
|
||||
requestqueue.o \
|
||||
util.o
|
||||
dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
|
||||
|
||||
dlm_device-y := device.o
|
||||
167
fs/dlm/ast.c
Normal file
167
fs/dlm/ast.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#include "dlm_internal.h"
|
||||
#include "lock.h"
|
||||
#include "ast.h"
|
||||
|
||||
#define WAKE_ASTS 0
|
||||
|
||||
static struct list_head ast_queue;
|
||||
static spinlock_t ast_queue_lock;
|
||||
static struct task_struct * astd_task;
|
||||
static unsigned long astd_wakeflags;
|
||||
static struct semaphore astd_running;
|
||||
|
||||
|
||||
void dlm_del_ast(struct dlm_lkb *lkb)
|
||||
{
|
||||
spin_lock(&ast_queue_lock);
|
||||
if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
|
||||
list_del(&lkb->lkb_astqueue);
|
||||
spin_unlock(&ast_queue_lock);
|
||||
}
|
||||
|
||||
void dlm_add_ast(struct dlm_lkb *lkb, int type)
|
||||
{
|
||||
spin_lock(&ast_queue_lock);
|
||||
if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
|
||||
kref_get(&lkb->lkb_ref);
|
||||
list_add_tail(&lkb->lkb_astqueue, &ast_queue);
|
||||
}
|
||||
lkb->lkb_ast_type |= type;
|
||||
spin_unlock(&ast_queue_lock);
|
||||
|
||||
set_bit(WAKE_ASTS, &astd_wakeflags);
|
||||
wake_up_process(astd_task);
|
||||
}
|
||||
|
||||
static void process_asts(void)
|
||||
{
|
||||
struct dlm_ls *ls = NULL;
|
||||
struct dlm_rsb *r = NULL;
|
||||
struct dlm_lkb *lkb;
|
||||
void (*cast) (long param);
|
||||
void (*bast) (long param, int mode);
|
||||
int type = 0, found, bmode;
|
||||
|
||||
for (;;) {
|
||||
found = FALSE;
|
||||
spin_lock(&ast_queue_lock);
|
||||
list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
|
||||
r = lkb->lkb_resource;
|
||||
ls = r->res_ls;
|
||||
|
||||
if (dlm_locking_stopped(ls))
|
||||
continue;
|
||||
|
||||
list_del(&lkb->lkb_astqueue);
|
||||
type = lkb->lkb_ast_type;
|
||||
lkb->lkb_ast_type = 0;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&ast_queue_lock);
|
||||
|
||||
if (!found)
|
||||
break;
|
||||
|
||||
cast = lkb->lkb_astaddr;
|
||||
bast = lkb->lkb_bastaddr;
|
||||
bmode = lkb->lkb_bastmode;
|
||||
|
||||
if ((type & AST_COMP) && cast)
|
||||
cast(lkb->lkb_astparam);
|
||||
|
||||
/* FIXME: Is it safe to look at lkb_grmode here
|
||||
without doing a lock_rsb() ?
|
||||
Look at other checks in v1 to avoid basts. */
|
||||
|
||||
if ((type & AST_BAST) && bast)
|
||||
if (!dlm_modes_compat(lkb->lkb_grmode, bmode))
|
||||
bast(lkb->lkb_astparam, bmode);
|
||||
|
||||
/* this removes the reference added by dlm_add_ast
|
||||
and may result in the lkb being freed */
|
||||
dlm_put_lkb(lkb);
|
||||
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static inline int no_asts(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock(&ast_queue_lock);
|
||||
ret = list_empty(&ast_queue);
|
||||
spin_unlock(&ast_queue_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dlm_astd(void *data)
|
||||
{
|
||||
while (!kthread_should_stop()) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!test_bit(WAKE_ASTS, &astd_wakeflags))
|
||||
schedule();
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
down(&astd_running);
|
||||
if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
|
||||
process_asts();
|
||||
up(&astd_running);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dlm_astd_wake(void)
|
||||
{
|
||||
if (!no_asts()) {
|
||||
set_bit(WAKE_ASTS, &astd_wakeflags);
|
||||
wake_up_process(astd_task);
|
||||
}
|
||||
}
|
||||
|
||||
int dlm_astd_start(void)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int error = 0;
|
||||
|
||||
INIT_LIST_HEAD(&ast_queue);
|
||||
spin_lock_init(&ast_queue_lock);
|
||||
init_MUTEX(&astd_running);
|
||||
|
||||
p = kthread_run(dlm_astd, NULL, "dlm_astd");
|
||||
if (IS_ERR(p))
|
||||
error = PTR_ERR(p);
|
||||
else
|
||||
astd_task = p;
|
||||
return error;
|
||||
}
|
||||
|
||||
void dlm_astd_stop(void)
|
||||
{
|
||||
kthread_stop(astd_task);
|
||||
}
|
||||
|
||||
void dlm_astd_suspend(void)
|
||||
{
|
||||
down(&astd_running);
|
||||
}
|
||||
|
||||
void dlm_astd_resume(void)
|
||||
{
|
||||
up(&astd_running);
|
||||
}
|
||||
|
||||
26
fs/dlm/ast.h
Normal file
26
fs/dlm/ast.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ASTD_DOT_H__
|
||||
#define __ASTD_DOT_H__
|
||||
|
||||
void dlm_add_ast(struct dlm_lkb *lkb, int type);
|
||||
void dlm_del_ast(struct dlm_lkb *lkb);
|
||||
|
||||
void dlm_astd_wake(void);
|
||||
int dlm_astd_start(void);
|
||||
void dlm_astd_stop(void);
|
||||
void dlm_astd_suspend(void);
|
||||
void dlm_astd_resume(void);
|
||||
|
||||
#endif
|
||||
|
||||
787
fs/dlm/config.c
Normal file
787
fs/dlm/config.c
Normal file
File diff suppressed because it is too large
Load Diff
42
fs/dlm/config.h
Normal file
42
fs/dlm/config.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __CONFIG_DOT_H__
|
||||
#define __CONFIG_DOT_H__
|
||||
|
||||
#define DLM_MAX_ADDR_COUNT 3
|
||||
|
||||
struct dlm_config_info {
|
||||
int tcp_port;
|
||||
int buffer_size;
|
||||
int rsbtbl_size;
|
||||
int lkbtbl_size;
|
||||
int dirtbl_size;
|
||||
int recover_timer;
|
||||
int toss_secs;
|
||||
int scan_secs;
|
||||
};
|
||||
|
||||
extern struct dlm_config_info dlm_config;
|
||||
|
||||
int dlm_config_init(void);
|
||||
void dlm_config_exit(void);
|
||||
int dlm_node_weight(char *lsname, int nodeid);
|
||||
int dlm_nodeid_list(char *lsname, int **ids_out);
|
||||
int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
|
||||
int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
|
||||
int dlm_our_nodeid(void);
|
||||
int dlm_our_addr(struct sockaddr_storage *addr, int num);
|
||||
|
||||
#endif /* __CONFIG_DOT_H__ */
|
||||
|
||||
310
fs/dlm/debug_fs.c
Normal file
310
fs/dlm/debug_fs.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "dlm_internal.h"
|
||||
|
||||
|
||||
static struct dentry *dlm_root;
|
||||
|
||||
struct rsb_iter {
|
||||
int entry;
|
||||
struct dlm_ls *ls;
|
||||
struct list_head *next;
|
||||
struct dlm_rsb *rsb;
|
||||
};
|
||||
|
||||
static char *print_lockmode(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case DLM_LOCK_IV:
|
||||
return "--";
|
||||
case DLM_LOCK_NL:
|
||||
return "NL";
|
||||
case DLM_LOCK_CR:
|
||||
return "CR";
|
||||
case DLM_LOCK_CW:
|
||||
return "CW";
|
||||
case DLM_LOCK_PR:
|
||||
return "PR";
|
||||
case DLM_LOCK_PW:
|
||||
return "PW";
|
||||
case DLM_LOCK_EX:
|
||||
return "EX";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
|
||||
struct dlm_rsb *res)
|
||||
{
|
||||
seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
|
||||
|
||||
if (lkb->lkb_status == DLM_LKSTS_CONVERT
|
||||
|| lkb->lkb_status == DLM_LKSTS_WAITING)
|
||||
seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
|
||||
|
||||
if (lkb->lkb_range) {
|
||||
/* FIXME: this warns on Alpha */
|
||||
if (lkb->lkb_status == DLM_LKSTS_CONVERT
|
||||
|| lkb->lkb_status == DLM_LKSTS_GRANTED)
|
||||
seq_printf(s, " %" PRIx64 "-%" PRIx64,
|
||||
lkb->lkb_range[GR_RANGE_START],
|
||||
lkb->lkb_range[GR_RANGE_END]);
|
||||
if (lkb->lkb_status == DLM_LKSTS_CONVERT
|
||||
|| lkb->lkb_status == DLM_LKSTS_WAITING)
|
||||
seq_printf(s, " (%" PRIx64 "-%" PRIx64 ")",
|
||||
lkb->lkb_range[RQ_RANGE_START],
|
||||
lkb->lkb_range[RQ_RANGE_END]);
|
||||
}
|
||||
|
||||
if (lkb->lkb_nodeid) {
|
||||
if (lkb->lkb_nodeid != res->res_nodeid)
|
||||
seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
|
||||
lkb->lkb_remid);
|
||||
else
|
||||
seq_printf(s, " Master: %08x", lkb->lkb_remid);
|
||||
}
|
||||
|
||||
if (lkb->lkb_wait_type)
|
||||
seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
|
||||
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
|
||||
static int print_resource(struct dlm_rsb *res, struct seq_file *s)
|
||||
{
|
||||
struct dlm_lkb *lkb;
|
||||
int i, lvblen = res->res_ls->ls_lvblen;
|
||||
|
||||
seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
|
||||
for (i = 0; i < res->res_length; i++) {
|
||||
if (isprint(res->res_name[i]))
|
||||
seq_printf(s, "%c", res->res_name[i]);
|
||||
else
|
||||
seq_printf(s, "%c", '.');
|
||||
}
|
||||
if (res->res_nodeid > 0)
|
||||
seq_printf(s, "\" \nLocal Copy, Master is node %d\n",
|
||||
res->res_nodeid);
|
||||
else if (res->res_nodeid == 0)
|
||||
seq_printf(s, "\" \nMaster Copy\n");
|
||||
else if (res->res_nodeid == -1)
|
||||
seq_printf(s, "\" \nLooking up master (lkid %x)\n",
|
||||
res->res_first_lkid);
|
||||
else
|
||||
seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid);
|
||||
|
||||
/* Print the LVB: */
|
||||
if (res->res_lvbptr) {
|
||||
seq_printf(s, "LVB: ");
|
||||
for (i = 0; i < lvblen; i++) {
|
||||
if (i == lvblen / 2)
|
||||
seq_printf(s, "\n ");
|
||||
seq_printf(s, "%02x ",
|
||||
(unsigned char) res->res_lvbptr[i]);
|
||||
}
|
||||
if (rsb_flag(res, RSB_VALNOTVALID))
|
||||
seq_printf(s, " (INVALID)");
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
|
||||
/* Print the locks attached to this resource */
|
||||
seq_printf(s, "Granted Queue\n");
|
||||
list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
|
||||
print_lock(s, lkb, res);
|
||||
|
||||
seq_printf(s, "Conversion Queue\n");
|
||||
list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
|
||||
print_lock(s, lkb, res);
|
||||
|
||||
seq_printf(s, "Waiting Queue\n");
|
||||
list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
|
||||
print_lock(s, lkb, res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsb_iter_next(struct rsb_iter *ri)
|
||||
{
|
||||
struct dlm_ls *ls = ri->ls;
|
||||
int i;
|
||||
|
||||
if (!ri->next) {
|
||||
top:
|
||||
/* Find the next non-empty hash bucket */
|
||||
for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
|
||||
read_lock(&ls->ls_rsbtbl[i].lock);
|
||||
if (!list_empty(&ls->ls_rsbtbl[i].list)) {
|
||||
ri->next = ls->ls_rsbtbl[i].list.next;
|
||||
read_unlock(&ls->ls_rsbtbl[i].lock);
|
||||
break;
|
||||
}
|
||||
read_unlock(&ls->ls_rsbtbl[i].lock);
|
||||
}
|
||||
ri->entry = i;
|
||||
|
||||
if (ri->entry >= ls->ls_rsbtbl_size)
|
||||
return 1;
|
||||
} else {
|
||||
i = ri->entry;
|
||||
read_lock(&ls->ls_rsbtbl[i].lock);
|
||||
ri->next = ri->next->next;
|
||||
if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
|
||||
/* End of list - move to next bucket */
|
||||
ri->next = NULL;
|
||||
ri->entry++;
|
||||
read_unlock(&ls->ls_rsbtbl[i].lock);
|
||||
goto top;
|
||||
}
|
||||
read_unlock(&ls->ls_rsbtbl[i].lock);
|
||||
}
|
||||
ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rsb_iter_free(struct rsb_iter *ri)
|
||||
{
|
||||
kfree(ri);
|
||||
}
|
||||
|
||||
static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
|
||||
{
|
||||
struct rsb_iter *ri;
|
||||
|
||||
ri = kmalloc(sizeof *ri, GFP_KERNEL);
|
||||
if (!ri)
|
||||
return NULL;
|
||||
|
||||
ri->ls = ls;
|
||||
ri->entry = 0;
|
||||
ri->next = NULL;
|
||||
|
||||
if (rsb_iter_next(ri)) {
|
||||
rsb_iter_free(ri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static void *seq_start(struct seq_file *file, loff_t *pos)
|
||||
{
|
||||
struct rsb_iter *ri;
|
||||
loff_t n = *pos;
|
||||
|
||||
ri = rsb_iter_init(file->private);
|
||||
if (!ri)
|
||||
return NULL;
|
||||
|
||||
while (n--) {
|
||||
if (rsb_iter_next(ri)) {
|
||||
rsb_iter_free(ri);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
|
||||
{
|
||||
struct rsb_iter *ri = iter_ptr;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
if (rsb_iter_next(ri)) {
|
||||
rsb_iter_free(ri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static void seq_stop(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
/* nothing for now */
|
||||
}
|
||||
|
||||
static int seq_show(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
struct rsb_iter *ri = iter_ptr;
|
||||
|
||||
print_resource(ri->rsb, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations dlm_seq_ops = {
|
||||
.start = seq_start,
|
||||
.next = seq_next,
|
||||
.stop = seq_stop,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
static int do_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq;
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &dlm_seq_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq = file->private_data;
|
||||
seq->private = inode->u.generic_ip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dlm_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = do_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
int dlm_create_debug_file(struct dlm_ls *ls)
|
||||
{
|
||||
ls->ls_debug_dentry = debugfs_create_file(ls->ls_name,
|
||||
S_IFREG | S_IRUGO,
|
||||
dlm_root,
|
||||
ls,
|
||||
&dlm_fops);
|
||||
return ls->ls_debug_dentry ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void dlm_delete_debug_file(struct dlm_ls *ls)
|
||||
{
|
||||
if (ls->ls_debug_dentry)
|
||||
debugfs_remove(ls->ls_debug_dentry);
|
||||
}
|
||||
|
||||
int dlm_register_debugfs(void)
|
||||
{
|
||||
dlm_root = debugfs_create_dir("dlm", NULL);
|
||||
return dlm_root ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void dlm_unregister_debugfs(void)
|
||||
{
|
||||
debugfs_remove(dlm_root);
|
||||
}
|
||||
|
||||
1084
fs/dlm/device.c
Normal file
1084
fs/dlm/device.c
Normal file
File diff suppressed because it is too large
Load Diff
423
fs/dlm/dir.c
Normal file
423
fs/dlm/dir.c
Normal file
@@ -0,0 +1,423 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#include "dlm_internal.h"
|
||||
#include "lockspace.h"
|
||||
#include "member.h"
|
||||
#include "lowcomms.h"
|
||||
#include "rcom.h"
|
||||
#include "config.h"
|
||||
#include "memory.h"
|
||||
#include "recover.h"
|
||||
#include "util.h"
|
||||
#include "lock.h"
|
||||
#include "dir.h"
|
||||
|
||||
|
||||
static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
|
||||
{
|
||||
spin_lock(&ls->ls_recover_list_lock);
|
||||
list_add(&de->list, &ls->ls_recover_list);
|
||||
spin_unlock(&ls->ls_recover_list_lock);
|
||||
}
|
||||
|
||||
static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
|
||||
{
|
||||
int found = FALSE;
|
||||
struct dlm_direntry *de;
|
||||
|
||||
spin_lock(&ls->ls_recover_list_lock);
|
||||
list_for_each_entry(de, &ls->ls_recover_list, list) {
|
||||
if (de->length == len) {
|
||||
list_del(&de->list);
|
||||
de->master_nodeid = 0;
|
||||
memset(de->name, 0, len);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ls->ls_recover_list_lock);
|
||||
|
||||
if (!found)
|
||||
de = allocate_direntry(ls, len);
|
||||
return de;
|
||||
}
|
||||
|
||||
void dlm_clear_free_entries(struct dlm_ls *ls)
|
||||
{
|
||||
struct dlm_direntry *de;
|
||||
|
||||
spin_lock(&ls->ls_recover_list_lock);
|
||||
while (!list_empty(&ls->ls_recover_list)) {
|
||||
de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
|
||||
list);
|
||||
list_del(&de->list);
|
||||
free_direntry(de);
|
||||
}
|
||||
spin_unlock(&ls->ls_recover_list_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the upper 16 bits of the hash value to select the directory node.
|
||||
* Low bits are used for distribution of rsb's among hash buckets on each node.
|
||||
*
|
||||
* To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
|
||||
* num_nodes to the hash value. This value in the desired range is used as an
|
||||
* offset into the sorted list of nodeid's to give the particular nodeid.
|
||||
*/
|
||||
|
||||
int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct dlm_member *memb = NULL;
|
||||
uint32_t node, n = 0;
|
||||
int nodeid;
|
||||
|
||||
if (ls->ls_num_nodes == 1) {
|
||||
nodeid = dlm_our_nodeid();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ls->ls_node_array) {
|
||||
node = (hash >> 16) % ls->ls_total_weight;
|
||||
nodeid = ls->ls_node_array[node];
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* make_member_array() failed to kmalloc ls_node_array... */
|
||||
|
||||
node = (hash >> 16) % ls->ls_num_nodes;
|
||||
|
||||
list_for_each(tmp, &ls->ls_nodes) {
|
||||
if (n++ != node)
|
||||
continue;
|
||||
memb = list_entry(tmp, struct dlm_member, list);
|
||||
break;
|
||||
}
|
||||
|
||||
DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
|
||||
ls->ls_num_nodes, n, node););
|
||||
nodeid = memb->nodeid;
|
||||
out:
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
int dlm_dir_nodeid(struct dlm_rsb *r)
|
||||
{
|
||||
return dlm_hash2nodeid(r->res_ls, r->res_hash);
|
||||
}
|
||||
|
||||
static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = jhash(name, len, 0);
|
||||
val &= (ls->ls_dirtbl_size - 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
|
||||
{
|
||||
uint32_t bucket;
|
||||
|
||||
bucket = dir_hash(ls, de->name, de->length);
|
||||
list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
|
||||
}
|
||||
|
||||
static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
|
||||
int namelen, uint32_t bucket)
|
||||
{
|
||||
struct dlm_direntry *de;
|
||||
|
||||
list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
|
||||
if (de->length == namelen && !memcmp(name, de->name, namelen))
|
||||
goto out;
|
||||
}
|
||||
de = NULL;
|
||||
out:
|
||||
return de;
|
||||
}
|
||||
|
||||
void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
|
||||
{
|
||||
struct dlm_direntry *de;
|
||||
uint32_t bucket;
|
||||
|
||||
bucket = dir_hash(ls, name, namelen);
|
||||
|
||||
write_lock(&ls->ls_dirtbl[bucket].lock);
|
||||
|
||||
de = search_bucket(ls, name, namelen, bucket);
|
||||
|
||||
if (!de) {
|
||||
log_error(ls, "remove fr %u none", nodeid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (de->master_nodeid != nodeid) {
|
||||
log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_del(&de->list);
|
||||
free_direntry(de);
|
||||
out:
|
||||
write_unlock(&ls->ls_dirtbl[bucket].lock);
|
||||
}
|
||||
|
||||
void dlm_dir_clear(struct dlm_ls *ls)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct dlm_direntry *de;
|
||||
int i;
|
||||
|
||||
DLM_ASSERT(list_empty(&ls->ls_recover_list), );
|
||||
|
||||
for (i = 0; i < ls->ls_dirtbl_size; i++) {
|
||||
write_lock(&ls->ls_dirtbl[i].lock);
|
||||
head = &ls->ls_dirtbl[i].list;
|
||||
while (!list_empty(head)) {
|
||||
de = list_entry(head->next, struct dlm_direntry, list);
|
||||
list_del(&de->list);
|
||||
put_free_de(ls, de);
|
||||
}
|
||||
write_unlock(&ls->ls_dirtbl[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
int dlm_recover_directory(struct dlm_ls *ls)
|
||||
{
|
||||
struct dlm_member *memb;
|
||||
struct dlm_direntry *de;
|
||||
char *b, *last_name = NULL;
|
||||
int error = -ENOMEM, last_len, count = 0;
|
||||
uint16_t namelen;
|
||||
|
||||
log_debug(ls, "dlm_recover_directory");
|
||||
|
||||
if (dlm_no_directory(ls))
|
||||
goto out_status;
|
||||
|
||||
dlm_dir_clear(ls);
|
||||
|
||||
last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
|
||||
if (!last_name)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(memb, &ls->ls_nodes, list) {
|
||||
memset(last_name, 0, DLM_RESNAME_MAXLEN);
|
||||
last_len = 0;
|
||||
|
||||
for (;;) {
|
||||
error = dlm_recovery_stopped(ls);
|
||||
if (error)
|
||||
goto out_free;
|
||||
|
||||
error = dlm_rcom_names(ls, memb->nodeid,
|
||||
last_name, last_len);
|
||||
if (error)
|
||||
goto out_free;
|
||||
|
||||
schedule();
|
||||
|
||||
/*
|
||||
* pick namelen/name pairs out of received buffer
|
||||
*/
|
||||
|
||||
b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
|
||||
|
||||
for (;;) {
|
||||
memcpy(&namelen, b, sizeof(uint16_t));
|
||||
namelen = be16_to_cpu(namelen);
|
||||
b += sizeof(uint16_t);
|
||||
|
||||
/* namelen of 0xFFFFF marks end of names for
|
||||
this node; namelen of 0 marks end of the
|
||||
buffer */
|
||||
|
||||
if (namelen == 0xFFFF)
|
||||
goto done;
|
||||
if (!namelen)
|
||||
break;
|
||||
|
||||
error = -ENOMEM;
|
||||
de = get_free_de(ls, namelen);
|
||||
if (!de)
|
||||
goto out_free;
|
||||
|
||||
de->master_nodeid = memb->nodeid;
|
||||
de->length = namelen;
|
||||
last_len = namelen;
|
||||
memcpy(de->name, b, namelen);
|
||||
memcpy(last_name, b, namelen);
|
||||
b += namelen;
|
||||
|
||||
add_entry_to_hash(ls, de);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
out_status:
|
||||
error = 0;
|
||||
dlm_set_recover_status(ls, DLM_RS_DIR);
|
||||
log_debug(ls, "dlm_recover_directory %d entries", count);
|
||||
out_free:
|
||||
kfree(last_name);
|
||||
out:
|
||||
dlm_clear_free_entries(ls);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
|
||||
int namelen, int *r_nodeid)
|
||||
{
|
||||
struct dlm_direntry *de, *tmp;
|
||||
uint32_t bucket;
|
||||
|
||||
bucket = dir_hash(ls, name, namelen);
|
||||
|
||||
write_lock(&ls->ls_dirtbl[bucket].lock);
|
||||
de = search_bucket(ls, name, namelen, bucket);
|
||||
if (de) {
|
||||
*r_nodeid = de->master_nodeid;
|
||||
write_unlock(&ls->ls_dirtbl[bucket].lock);
|
||||
if (*r_nodeid == nodeid)
|
||||
return -EEXIST;
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_unlock(&ls->ls_dirtbl[bucket].lock);
|
||||
|
||||
de = allocate_direntry(ls, namelen);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
|
||||
de->master_nodeid = nodeid;
|
||||
de->length = namelen;
|
||||
memcpy(de->name, name, namelen);
|
||||
|
||||
write_lock(&ls->ls_dirtbl[bucket].lock);
|
||||
tmp = search_bucket(ls, name, namelen, bucket);
|
||||
if (tmp) {
|
||||
free_direntry(de);
|
||||
de = tmp;
|
||||
} else {
|
||||
list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
|
||||
}
|
||||
*r_nodeid = de->master_nodeid;
|
||||
write_unlock(&ls->ls_dirtbl[bucket].lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
|
||||
int *r_nodeid)
|
||||
{
|
||||
return get_entry(ls, nodeid, name, namelen, r_nodeid);
|
||||
}
|
||||
|
||||
/* Copy the names of master rsb's into the buffer provided.
|
||||
Only select names whose dir node is the given nodeid. */
|
||||
|
||||
void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
|
||||
char *outbuf, int outlen, int nodeid)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct dlm_rsb *start_r = NULL, *r = NULL;
|
||||
int offset = 0, start_namelen, error, dir_nodeid;
|
||||
char *start_name;
|
||||
uint16_t be_namelen;
|
||||
|
||||
/*
|
||||
* Find the rsb where we left off (or start again)
|
||||
*/
|
||||
|
||||
start_namelen = inlen;
|
||||
start_name = inbuf;
|
||||
|
||||
if (start_namelen > 1) {
|
||||
/*
|
||||
* We could also use a find_rsb_root() function here that
|
||||
* searched the ls_root_list.
|
||||
*/
|
||||
error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER,
|
||||
&start_r);
|
||||
DLM_ASSERT(!error && start_r,
|
||||
printk("error %d\n", error););
|
||||
DLM_ASSERT(!list_empty(&start_r->res_root_list),
|
||||
dlm_print_rsb(start_r););
|
||||
dlm_put_rsb(start_r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send rsb names for rsb's we're master of and whose directory node
|
||||
* matches the requesting node.
|
||||
*/
|
||||
|
||||
down_read(&ls->ls_root_sem);
|
||||
if (start_r)
|
||||
list = start_r->res_root_list.next;
|
||||
else
|
||||
list = ls->ls_root_list.next;
|
||||
|
||||
for (offset = 0; list != &ls->ls_root_list; list = list->next) {
|
||||
r = list_entry(list, struct dlm_rsb, res_root_list);
|
||||
if (r->res_nodeid)
|
||||
continue;
|
||||
|
||||
dir_nodeid = dlm_dir_nodeid(r);
|
||||
if (dir_nodeid != nodeid)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The block ends when we can't fit the following in the
|
||||
* remaining buffer space:
|
||||
* namelen (uint16_t) +
|
||||
* name (r->res_length) +
|
||||
* end-of-block record 0x0000 (uint16_t)
|
||||
*/
|
||||
|
||||
if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
|
||||
/* Write end-of-block record */
|
||||
be_namelen = 0;
|
||||
memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
|
||||
offset += sizeof(uint16_t);
|
||||
goto out;
|
||||
}
|
||||
|
||||
be_namelen = cpu_to_be16(r->res_length);
|
||||
memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
|
||||
offset += sizeof(uint16_t);
|
||||
memcpy(outbuf + offset, r->res_name, r->res_length);
|
||||
offset += r->res_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've reached the end of the list (and there's room) write a
|
||||
* terminating record.
|
||||
*/
|
||||
|
||||
if ((list == &ls->ls_root_list) &&
|
||||
(offset + sizeof(uint16_t) <= outlen)) {
|
||||
be_namelen = 0xFFFF;
|
||||
memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
|
||||
offset += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
out:
|
||||
up_read(&ls->ls_root_sem);
|
||||
}
|
||||
|
||||
30
fs/dlm/dir.h
Normal file
30
fs/dlm/dir.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __DIR_DOT_H__
|
||||
#define __DIR_DOT_H__
|
||||
|
||||
|
||||
int dlm_dir_nodeid(struct dlm_rsb *rsb);
|
||||
int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
|
||||
void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
|
||||
void dlm_dir_clear(struct dlm_ls *ls);
|
||||
void dlm_clear_free_entries(struct dlm_ls *ls);
|
||||
int dlm_recover_directory(struct dlm_ls *ls);
|
||||
int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
|
||||
int *r_nodeid);
|
||||
void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
|
||||
char *outbuf, int outlen, int nodeid);
|
||||
|
||||
#endif /* __DIR_DOT_H__ */
|
||||
|
||||
518
fs/dlm/dlm_internal.h
Normal file
518
fs/dlm/dlm_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
3610
fs/dlm/lock.c
Normal file
3610
fs/dlm/lock.c
Normal file
File diff suppressed because it is too large
Load Diff
50
fs/dlm/lock.h
Normal file
50
fs/dlm/lock.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __LOCK_DOT_H__
|
||||
#define __LOCK_DOT_H__
|
||||
|
||||
void dlm_print_rsb(struct dlm_rsb *r);
|
||||
int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
|
||||
int dlm_modes_compat(int mode1, int mode2);
|
||||
int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
|
||||
unsigned int flags, struct dlm_rsb **r_ret);
|
||||
void dlm_put_rsb(struct dlm_rsb *r);
|
||||
void dlm_hold_rsb(struct dlm_rsb *r);
|
||||
int dlm_put_lkb(struct dlm_lkb *lkb);
|
||||
void dlm_scan_rsbs(struct dlm_ls *ls);
|
||||
|
||||
int dlm_purge_locks(struct dlm_ls *ls);
|
||||
void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
|
||||
int dlm_grant_after_purge(struct dlm_ls *ls);
|
||||
int dlm_recover_waiters_post(struct dlm_ls *ls);
|
||||
void dlm_recover_waiters_pre(struct dlm_ls *ls);
|
||||
int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
|
||||
int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
|
||||
|
||||
static inline int is_master(struct dlm_rsb *r)
|
||||
{
|
||||
return !r->res_nodeid;
|
||||
}
|
||||
|
||||
static inline void lock_rsb(struct dlm_rsb *r)
|
||||
{
|
||||
down(&r->res_sem);
|
||||
}
|
||||
|
||||
static inline void unlock_rsb(struct dlm_rsb *r)
|
||||
{
|
||||
up(&r->res_sem);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
666
fs/dlm/lockspace.c
Normal file
666
fs/dlm/lockspace.c
Normal file
File diff suppressed because it is too large
Load Diff
24
fs/dlm/lockspace.h
Normal file
24
fs/dlm/lockspace.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __LOCKSPACE_DOT_H__
|
||||
#define __LOCKSPACE_DOT_H__
|
||||
|
||||
int dlm_lockspace_init(void);
|
||||
void dlm_lockspace_exit(void);
|
||||
struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
|
||||
struct dlm_ls *dlm_find_lockspace_local(void *id);
|
||||
void dlm_put_lockspace(struct dlm_ls *ls);
|
||||
|
||||
#endif /* __LOCKSPACE_DOT_H__ */
|
||||
|
||||
1218
fs/dlm/lowcomms.c
Normal file
1218
fs/dlm/lowcomms.c
Normal file
File diff suppressed because it is too large
Load Diff
25
fs/dlm/lowcomms.h
Normal file
25
fs/dlm/lowcomms.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __LOWCOMMS_DOT_H__
|
||||
#define __LOWCOMMS_DOT_H__
|
||||
|
||||
int dlm_lowcomms_init(void);
|
||||
void dlm_lowcomms_exit(void);
|
||||
int dlm_lowcomms_start(void);
|
||||
void dlm_lowcomms_stop(void);
|
||||
void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc);
|
||||
void dlm_lowcomms_commit_buffer(void *mh);
|
||||
|
||||
#endif /* __LOWCOMMS_DOT_H__ */
|
||||
|
||||
18
fs/dlm/lvb_table.h
Normal file
18
fs/dlm/lvb_table.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __LVB_TABLE_DOT_H__
|
||||
#define __LVB_TABLE_DOT_H__
|
||||
|
||||
extern const int dlm_lvb_operations[8][8];
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user