From e7fd41792fc0ee52a05fcaac87511f118328d147 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 09:30:29 +0000 Subject: [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 Signed-off-by: Steve Whitehouse --- fs/dlm/dlm_internal.h | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 fs/dlm/dlm_internal.h (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h new file mode 100644 index 00000000000000..0020cd07baf708 --- /dev/null +++ b/fs/dlm/dlm_internal.h @@ -0,0 +1,518 @@ +/****************************************************************************** +******************************************************************************* +** +** 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 __DLM_INTERNAL_DOT_H__ +#define __DLM_INTERNAL_DOT_H__ + +/* + * This is the main header file to be included in each DLM source file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DLM_LOCKSPACE_LEN 64 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#if (BITS_PER_LONG == 64) +#define PRIx64 "lx" +#else +#define PRIx64 "Lx" +#endif + +/* Size of the temp buffer midcomms allocates on the stack. + We try to make this large enough so most messages fit. + FIXME: should sctp make this unnecessary? */ + +#define DLM_INBUF_LEN 148 + +struct dlm_ls; +struct dlm_lkb; +struct dlm_rsb; +struct dlm_member; +struct dlm_lkbtable; +struct dlm_rsbtable; +struct dlm_dirtable; +struct dlm_direntry; +struct dlm_recover; +struct dlm_header; +struct dlm_message; +struct dlm_rcom; +struct dlm_mhandle; + +#define log_print(fmt, args...) \ + printk(KERN_ERR "dlm: "fmt"\n" , ##args) +#define log_error(ls, fmt, args...) \ + printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args) + +#ifdef DLM_LOG_DEBUG +#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args) +#else +#define log_debug(ls, fmt, args...) +#endif + +#define DLM_ASSERT(x, do) \ +{ \ + if (!(x)) \ + { \ + printk(KERN_ERR "\nDLM: Assertion failed on line %d of file %s\n" \ + "DLM: assertion: \"%s\"\n" \ + "DLM: time = %lu\n", \ + __LINE__, __FILE__, #x, jiffies); \ + {do} \ + printk("\n"); \ + BUG(); \ + panic("DLM: Record message above and reboot.\n"); \ + } \ +} + + +struct dlm_direntry { + struct list_head list; + uint32_t master_nodeid; + uint16_t length; + char name[1]; +}; + +struct dlm_dirtable { + struct list_head list; + rwlock_t lock; +}; + +struct dlm_rsbtable { + struct list_head list; + struct list_head toss; + rwlock_t lock; +}; + +struct dlm_lkbtable { + struct list_head list; + rwlock_t lock; + uint16_t counter; +}; + +/* + * Lockspace member (per node in a ls) + */ + +struct dlm_member { + struct list_head list; + int nodeid; + int weight; +}; + +/* + * Save and manage recovery state for a lockspace. + */ + +struct dlm_recover { + struct list_head list; + int *nodeids; + int node_count; + uint64_t seq; +}; + +/* + * Pass input args to second stage locking function. + */ + +struct dlm_args { + uint32_t flags; + void *astaddr; + long astparam; + void *bastaddr; + int mode; + struct dlm_lksb *lksb; + struct dlm_range *range; +}; + + +/* + * Lock block + * + * A lock can be one of three types: + * + * local copy lock is mastered locally + * (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set) + * process copy lock is mastered on a remote node + * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set) + * master copy master node's copy of a lock owned by remote node + * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set) + * + * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or + * dlm_unlock. The dlm does not modify these or use any private flags in + * this field; it only contains DLM_LKF_ flags from dlm.h. These flags + * are sent as-is to the remote master when the lock is remote. + * + * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h. + * Some internal flags are shared between the master and process nodes; + * these shared flags are kept in the lower two bytes. One of these + * flags set on the master copy will be propagated to the process copy + * and v.v. Other internal flags are private to the master or process + * node (e.g. DLM_IFL_MSTCPY). These are kept in the high two bytes. + * + * lkb_sbflags: status block flags. These flags are copied directly into + * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion + * ast. All defined in dlm.h with DLM_SBF_ prefix. + * + * lkb_status: the lock status indicates which rsb queue the lock is + * on, grant, convert, or wait. DLM_LKSTS_ WAITING/GRANTED/CONVERT + * + * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a + * reply is needed. Only set when the lkb is on the lockspace waiters + * list awaiting a reply from a remote node. + * + * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb + * is a master copy, nodeid specifies the remote lock holder, when the + * lkb is a process copy, the nodeid specifies the lock master. + */ + +/* lkb_ast_type */ + +#define AST_COMP 1 +#define AST_BAST 2 + +/* lkb_range[] */ + +#define GR_RANGE_START 0 +#define GR_RANGE_END 1 +#define RQ_RANGE_START 2 +#define RQ_RANGE_END 3 + +/* lkb_status */ + +#define DLM_LKSTS_WAITING 1 +#define DLM_LKSTS_GRANTED 2 +#define DLM_LKSTS_CONVERT 3 + +/* lkb_flags */ + +#define DLM_IFL_MSTCPY 0x00010000 +#define DLM_IFL_RESEND 0x00020000 +#define DLM_IFL_RANGE 0x00000001 + +struct dlm_lkb { + struct dlm_rsb *lkb_resource; /* the rsb */ + struct kref lkb_ref; + int lkb_nodeid; /* copied from rsb */ + int lkb_ownpid; /* pid of lock owner */ + uint32_t lkb_id; /* our lock ID */ + uint32_t lkb_remid; /* lock ID on remote partner */ + uint32_t lkb_exflags; /* external flags from caller */ + uint32_t lkb_sbflags; /* lksb flags */ + uint32_t lkb_flags; /* internal flags */ + uint32_t lkb_lvbseq; /* lvb sequence number */ + + int8_t lkb_status; /* granted, waiting, convert */ + int8_t lkb_rqmode; /* requested lock mode */ + int8_t lkb_grmode; /* granted lock mode */ + int8_t lkb_bastmode; /* requested mode */ + int8_t lkb_highbast; /* highest mode bast sent for */ + + int8_t lkb_wait_type; /* type of reply waiting for */ + int8_t lkb_ast_type; /* type of ast queued for */ + + struct list_head lkb_idtbl_list; /* lockspace lkbtbl */ + struct list_head lkb_statequeue; /* rsb g/c/w list */ + struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */ + struct list_head lkb_wait_reply; /* waiting for remote reply */ + struct list_head lkb_astqueue; /* need ast to be sent */ + + uint64_t *lkb_range; /* array of gr/rq ranges */ + char *lkb_lvbptr; + struct dlm_lksb *lkb_lksb; /* caller's status block */ + void *lkb_astaddr; /* caller's ast function */ + void *lkb_bastaddr; /* caller's bast function */ + long lkb_astparam; /* caller's ast arg */ +}; + + +struct dlm_rsb { + struct dlm_ls *res_ls; /* the lockspace */ + struct kref res_ref; + struct semaphore res_sem; + unsigned long res_flags; + int res_length; /* length of rsb name */ + int res_nodeid; + uint32_t res_lvbseq; + uint32_t res_hash; + uint32_t res_bucket; /* rsbtbl */ + unsigned long res_toss_time; + uint32_t res_first_lkid; + struct list_head res_lookup; /* lkbs waiting on first */ + struct list_head res_hashchain; /* rsbtbl */ + struct list_head res_grantqueue; + struct list_head res_convertqueue; + struct list_head res_waitqueue; + + struct list_head res_root_list; /* used for recovery */ + struct list_head res_recover_list; /* used for recovery */ + int res_recover_locks_count; + + char *res_lvbptr; + char res_name[1]; +}; + +/* find_rsb() flags */ + +#define R_MASTER 1 /* only return rsb if it's a master */ +#define R_CREATE 2 /* create/add rsb if not found */ + +/* rsb_flags */ + +enum rsb_flags { + RSB_MASTER_UNCERTAIN, + RSB_VALNOTVALID, + RSB_VALNOTVALID_PREV, + RSB_NEW_MASTER, + RSB_NEW_MASTER2, + RSB_RECOVER_CONVERT, +}; + +static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + __set_bit(flag, &r->res_flags); +} + +static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + __clear_bit(flag, &r->res_flags); +} + +static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + return test_bit(flag, &r->res_flags); +} + + +/* dlm_header is first element of all structs sent between nodes */ + +#define DLM_HEADER_MAJOR 0x00020000 +#define DLM_HEADER_MINOR 0x00000001 + +#define DLM_MSG 1 +#define DLM_RCOM 2 + +struct dlm_header { + uint32_t h_version; + uint32_t h_lockspace; + uint32_t h_nodeid; /* nodeid of sender */ + uint16_t h_length; + uint8_t h_cmd; /* DLM_MSG, DLM_RCOM */ + uint8_t h_pad; +}; + + +#define DLM_MSG_REQUEST 1 +#define DLM_MSG_CONVERT 2 +#define DLM_MSG_UNLOCK 3 +#define DLM_MSG_CANCEL 4 +#define DLM_MSG_REQUEST_REPLY 5 +#define DLM_MSG_CONVERT_REPLY 6 +#define DLM_MSG_UNLOCK_REPLY 7 +#define DLM_MSG_CANCEL_REPLY 8 +#define DLM_MSG_GRANT 9 +#define DLM_MSG_BAST 10 +#define DLM_MSG_LOOKUP 11 +#define DLM_MSG_REMOVE 12 +#define DLM_MSG_LOOKUP_REPLY 13 + +struct dlm_message { + struct dlm_header m_header; + uint32_t m_type; /* DLM_MSG_ */ + uint32_t m_nodeid; + uint32_t m_pid; + uint32_t m_lkid; /* lkid on sender */ + uint32_t m_remid; /* lkid on receiver */ + uint32_t m_parent_lkid; + uint32_t m_parent_remid; + uint32_t m_exflags; + uint32_t m_sbflags; + uint32_t m_flags; + uint32_t m_lvbseq; + uint32_t m_hash; + int m_status; + int m_grmode; + int m_rqmode; + int m_bastmode; + int m_asts; + int m_result; /* 0 or -EXXX */ + uint64_t m_range[2]; + char m_extra[0]; /* name or lvb */ +}; + + +#define DLM_RS_NODES 0x00000001 +#define DLM_RS_NODES_ALL 0x00000002 +#define DLM_RS_DIR 0x00000004 +#define DLM_RS_DIR_ALL 0x00000008 +#define DLM_RS_LOCKS 0x00000010 +#define DLM_RS_LOCKS_ALL 0x00000020 +#define DLM_RS_DONE 0x00000040 +#define DLM_RS_DONE_ALL 0x00000080 + +#define DLM_RCOM_STATUS 1 +#define DLM_RCOM_NAMES 2 +#define DLM_RCOM_LOOKUP 3 +#define DLM_RCOM_LOCK 4 +#define DLM_RCOM_STATUS_REPLY 5 +#define DLM_RCOM_NAMES_REPLY 6 +#define DLM_RCOM_LOOKUP_REPLY 7 +#define DLM_RCOM_LOCK_REPLY 8 + +struct dlm_rcom { + struct dlm_header rc_header; + uint32_t rc_type; /* DLM_RCOM_ */ + int rc_result; /* multi-purpose */ + uint64_t rc_id; /* match reply with request */ + char rc_buf[0]; +}; + +struct rcom_config { + uint32_t rf_lvblen; + uint32_t rf_lsflags; + uint64_t rf_unused; +}; + +struct rcom_lock { + uint32_t rl_ownpid; + uint32_t rl_lkid; + uint32_t rl_remid; + uint32_t rl_parent_lkid; + uint32_t rl_parent_remid; + uint32_t rl_exflags; + uint32_t rl_flags; + uint32_t rl_lvbseq; + int rl_result; + int8_t rl_rqmode; + int8_t rl_grmode; + int8_t rl_status; + int8_t rl_asts; + uint16_t rl_wait_type; + uint16_t rl_namelen; + uint64_t rl_range[4]; + char rl_name[DLM_RESNAME_MAXLEN]; + char rl_lvb[0]; +}; + +struct dlm_ls { + struct list_head ls_list; /* list of lockspaces */ + uint32_t ls_global_id; /* global unique lockspace ID */ + uint32_t ls_exflags; + int ls_lvblen; + int ls_count; /* reference count */ + unsigned long ls_flags; /* LSFL_ */ + struct kobject ls_kobj; + + struct dlm_rsbtable *ls_rsbtbl; + uint32_t ls_rsbtbl_size; + + struct dlm_lkbtable *ls_lkbtbl; + uint32_t ls_lkbtbl_size; + + struct dlm_dirtable *ls_dirtbl; + uint32_t ls_dirtbl_size; + + struct semaphore ls_waiters_sem; + struct list_head ls_waiters; /* lkbs needing a reply */ + + struct list_head ls_nodes; /* current nodes in ls */ + struct list_head ls_nodes_gone; /* dead node list, recovery */ + int ls_num_nodes; /* number of nodes in ls */ + int ls_low_nodeid; + int ls_total_weight; + int *ls_node_array; + + struct dlm_rsb ls_stub_rsb; /* for returning errors */ + struct dlm_lkb ls_stub_lkb; /* for returning errors */ + struct dlm_message ls_stub_ms; /* for faking a reply */ + + struct dentry *ls_debug_dentry; /* debugfs */ + + wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ + int ls_uevent_result; + + /* recovery related */ + + struct timer_list ls_timer; + struct task_struct *ls_recoverd_task; + struct semaphore ls_recoverd_active; + spinlock_t ls_recover_lock; + uint32_t ls_recover_status; /* DLM_RS_ */ + uint64_t ls_recover_seq; + struct dlm_recover *ls_recover_args; + struct rw_semaphore ls_in_recovery; /* block local requests */ + struct list_head ls_requestqueue;/* queue remote requests */ + struct semaphore ls_requestqueue_lock; + char *ls_recover_buf; + struct list_head ls_recover_list; + spinlock_t ls_recover_list_lock; + int ls_recover_list_count; + wait_queue_head_t ls_wait_general; + + struct list_head ls_root_list; /* root resources */ + struct rw_semaphore ls_root_sem; /* protect root_list */ + + int ls_namelen; + char ls_name[1]; +}; + +#define LSFL_WORK 0 +#define LSFL_RUNNING 1 +#define LSFL_RECOVERY_STOP 2 +#define LSFL_RCOM_READY 3 +#define LSFL_UEVENT_WAIT 4 + +static inline int dlm_locking_stopped(struct dlm_ls *ls) +{ + return !test_bit(LSFL_RUNNING, &ls->ls_flags); +} + +static inline int dlm_recovery_stopped(struct dlm_ls *ls) +{ + return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags); +} + +static inline int dlm_no_directory(struct dlm_ls *ls) +{ + return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0; +} + +#endif /* __DLM_INTERNAL_DOT_H__ */ + -- cgit 1.2.3-korg From 901359256b2666f52a3a7d3f31927677e91b3a2a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 20 Jan 2006 08:47:07 +0000 Subject: [DLM] Update DLM to the latest patch level Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- fs/dlm/ast.c | 16 ++++++------ fs/dlm/config.c | 20 +++++++------- fs/dlm/debug_fs.c | 4 +-- fs/dlm/device.c | 55 +++++++++++++++++++++++---------------- fs/dlm/dir.c | 4 +-- fs/dlm/dlm_internal.h | 23 ++++------------ fs/dlm/lock.c | 72 +++++++++++++++++++++++++-------------------------- fs/dlm/lock.h | 4 +-- fs/dlm/lockspace.c | 21 +++++++-------- fs/dlm/member.c | 17 ++++++------ fs/dlm/midcomms.c | 2 +- fs/dlm/recover.c | 18 ++++++------- fs/dlm/recoverd.c | 16 ++++++------ fs/dlm/requestqueue.c | 26 +++++++++---------- 14 files changed, 147 insertions(+), 151 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 2bd1c5e1a72c73..57bdf09b520a8a 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -21,7 +21,7 @@ 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; +static struct mutex astd_running; void dlm_del_ast(struct dlm_lkb *lkb) @@ -56,7 +56,7 @@ static void process_asts(void) int type = 0, found, bmode; for (;;) { - found = FALSE; + found = 0; spin_lock(&ast_queue_lock); list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { r = lkb->lkb_resource; @@ -68,7 +68,7 @@ static void process_asts(void) list_del(&lkb->lkb_astqueue); type = lkb->lkb_ast_type; lkb->lkb_ast_type = 0; - found = TRUE; + found = 1; break; } spin_unlock(&ast_queue_lock); @@ -117,10 +117,10 @@ static int dlm_astd(void *data) schedule(); set_current_state(TASK_RUNNING); - down(&astd_running); + mutex_lock(&astd_running); if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) process_asts(); - up(&astd_running); + mutex_unlock(&astd_running); } return 0; } @@ -140,7 +140,7 @@ int dlm_astd_start(void) INIT_LIST_HEAD(&ast_queue); spin_lock_init(&ast_queue_lock); - init_MUTEX(&astd_running); + mutex_init(&astd_running); p = kthread_run(dlm_astd, NULL, "dlm_astd"); if (IS_ERR(p)) @@ -157,11 +157,11 @@ void dlm_astd_stop(void) void dlm_astd_suspend(void) { - down(&astd_running); + mutex_lock(&astd_running); } void dlm_astd_resume(void) { - up(&astd_running); + mutex_unlock(&astd_running); } diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 024ace9973a81b..87df9616415e5d 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -162,7 +162,7 @@ struct spaces { struct space { struct config_group group; struct list_head members; - struct semaphore members_lock; + struct mutex members_lock; int members_count; }; @@ -374,7 +374,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) sp->group.default_groups[1] = NULL; INIT_LIST_HEAD(&sp->members); - init_MUTEX(&sp->members_lock); + mutex_init(&sp->members_lock); sp->members_count = 0; return &sp->group; @@ -453,10 +453,10 @@ static struct config_item *make_node(struct config_group *g, const char *name) nd->nodeid = -1; nd->weight = 1; /* default weight of 1 if none is set */ - down(&sp->members_lock); + mutex_lock(&sp->members_lock); list_add(&nd->list, &sp->members); sp->members_count++; - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); return &nd->item; } @@ -466,10 +466,10 @@ static void drop_node(struct config_group *g, struct config_item *i) struct space *sp = to_space(g->cg_item.ci_parent); struct node *nd = to_node(i); - down(&sp->members_lock); + mutex_lock(&sp->members_lock); list_del(&nd->list); sp->members_count--; - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); config_item_put(i); } @@ -677,7 +677,7 @@ int dlm_nodeid_list(char *lsname, int **ids_out) if (!sp) return -EEXIST; - down(&sp->members_lock); + mutex_lock(&sp->members_lock); if (!sp->members_count) { rv = 0; goto out; @@ -698,7 +698,7 @@ int dlm_nodeid_list(char *lsname, int **ids_out) *ids_out = ids; out: - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); put_space(sp); return rv; } @@ -713,14 +713,14 @@ int dlm_node_weight(char *lsname, int nodeid) if (!sp) goto out; - down(&sp->members_lock); + mutex_lock(&sp->members_lock); list_for_each_entry(nd, &sp->members, list) { if (nd->nodeid != nodeid) continue; w = nd->weight; break; } - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); put_space(sp); out: return w; diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 98b49a1ece4713..5080bbffd586a7 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -63,12 +63,12 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, /* FIXME: this warns on Alpha */ if (lkb->lkb_status == DLM_LKSTS_CONVERT || lkb->lkb_status == DLM_LKSTS_GRANTED) - seq_printf(s, " %" PRIx64 "-%" PRIx64, + seq_printf(s, " %llx-%llx", 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 ")", + seq_printf(s, " (%llx-%llx)", lkb->lkb_range[RQ_RANGE_START], lkb->lkb_range[RQ_RANGE_END]); } diff --git a/fs/dlm/device.c b/fs/dlm/device.c index a8bf600ed13dd7..899d4f92a4d714 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -43,7 +43,7 @@ static struct file_operations _dlm_fops; static const char *name_prefix="dlm"; static struct list_head user_ls_list; -static struct semaphore user_ls_lock; +static struct mutex user_ls_lock; /* Lock infos are stored in here indexed by lock ID */ static DEFINE_IDR(lockinfo_idr); @@ -53,6 +53,7 @@ static rwlock_t lockinfo_lock; #define LI_FLAG_COMPLETE 1 #define LI_FLAG_FIRSTLOCK 2 #define LI_FLAG_PERSISTENT 3 +#define LI_FLAG_ONLIST 4 /* flags in ls_flags*/ #define LS_FLAG_DELETED 1 @@ -211,18 +212,18 @@ static struct user_ls *find_lockspace(int minor) { struct user_ls *lsinfo; - down(&user_ls_lock); + mutex_lock(&user_ls_lock); lsinfo = __find_lockspace(minor); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return lsinfo; } static void add_lockspace_to_list(struct user_ls *lsinfo) { - down(&user_ls_lock); + mutex_lock(&user_ls_lock); list_add(&lsinfo->ls_list, &user_ls_list); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); } /* Register a lockspace with the DLM and create a misc @@ -235,12 +236,11 @@ static int register_lockspace(char *name, struct user_ls **ls, int flags) namelen = strlen(name)+strlen(name_prefix)+2; - newls = kmalloc(sizeof(struct user_ls), GFP_KERNEL); + newls = kzalloc(sizeof(struct user_ls), GFP_KERNEL); if (!newls) return -ENOMEM; - memset(newls, 0, sizeof(struct user_ls)); - newls->ls_miscinfo.name = kmalloc(namelen, GFP_KERNEL); + newls->ls_miscinfo.name = kzalloc(namelen, GFP_KERNEL); if (!newls->ls_miscinfo.name) { kfree(newls); return -ENOMEM; @@ -277,7 +277,7 @@ static int register_lockspace(char *name, struct user_ls **ls, int flags) return 0; } -/* Called with the user_ls_lock semaphore held */ +/* Called with the user_ls_lock mutex held */ static int unregister_lockspace(struct user_ls *lsinfo, int force) { int status; @@ -305,11 +305,10 @@ static int unregister_lockspace(struct user_ls *lsinfo, int force) static void add_to_astqueue(struct lock_info *li, void *astaddr, void *astparam, int lvb_updated) { - struct ast_info *ast = kmalloc(sizeof(struct ast_info), GFP_KERNEL); + struct ast_info *ast = kzalloc(sizeof(struct ast_info), GFP_KERNEL); if (!ast) return; - memset(ast, 0, sizeof(*ast)); ast->result.user_astparam = astparam; ast->result.user_astaddr = astaddr; ast->result.user_lksb = li->li_user_lksb; @@ -382,6 +381,7 @@ static void ast_routine(void *param) spin_lock(&li->li_file->fi_li_lock); list_del(&li->li_ownerqueue); + clear_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&li->li_file->fi_li_lock); release_lockinfo(li); return; @@ -437,7 +437,7 @@ static int dlm_open(struct inode *inode, struct file *file) if (!lsinfo) return -ENOENT; - f = kmalloc(sizeof(struct file_info), GFP_KERNEL); + f = kzalloc(sizeof(struct file_info), GFP_KERNEL); if (!f) return -ENOMEM; @@ -570,7 +570,7 @@ static int dlm_close(struct inode *inode, struct file *file) * then free the struct. If it's an AUTOFREE lockspace * then free the whole thing. */ - down(&user_ls_lock); + mutex_lock(&user_ls_lock); if (atomic_dec_and_test(&lsinfo->ls_refcnt)) { if (lsinfo->ls_lockspace) { @@ -582,7 +582,7 @@ static int dlm_close(struct inode *inode, struct file *file) kfree(lsinfo); } } - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); put_file_info(f); /* Restore signals */ @@ -620,10 +620,10 @@ static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - down(&user_ls_lock); + mutex_lock(&user_ls_lock); lsinfo = __find_lockspace(kparams->minor); if (!lsinfo) { - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return -EINVAL; } @@ -631,7 +631,7 @@ static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, force = 2; status = unregister_lockspace(lsinfo, force); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return status; } @@ -752,7 +752,7 @@ static struct lock_info *allocate_lockinfo(struct file_info *fi, uint8_t cmd, if (!try_module_get(THIS_MODULE)) return NULL; - li = kmalloc(sizeof(struct lock_info), GFP_KERNEL); + li = kzalloc(sizeof(struct lock_info), GFP_KERNEL); if (li) { li->li_magic = LOCKINFO_MAGIC; li->li_file = fi; @@ -800,8 +800,10 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, /* If this is a persistent lock we will have to create a lockinfo again */ - if (!li && DLM_LKF_PERSISTENT) { + if (!li && (kparams->flags & DLM_LKF_PERSISTENT)) { li = allocate_lockinfo(fi, cmd, kparams); + if (!li) + return -ENOMEM; li->li_lksb.sb_lkid = kparams->lkid; li->li_castaddr = kparams->castaddr; @@ -887,6 +889,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, spin_lock(&fi->fi_li_lock); list_add(&li->li_ownerqueue, &fi->fi_li_list); + set_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); if (add_lockinfo(li)) printk(KERN_WARNING "Add lockinfo failed\n"); @@ -914,12 +917,13 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, li = get_lockinfo(kparams->lkid); if (!li) { li = allocate_lockinfo(fi, cmd, kparams); + if (!li) + return -ENOMEM; spin_lock(&fi->fi_li_lock); list_add(&li->li_ownerqueue, &fi->fi_li_list); + set_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); } - if (!li) - return -ENOMEM; if (li->li_magic != LOCKINFO_MAGIC) return -EINVAL; @@ -932,6 +936,12 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, if (kparams->flags & DLM_LKF_CANCEL && li->li_grmode != -1) convert_cancel = 1; + /* Wait until dlm_lock() has completed */ + if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) { + down(&li->li_firstlock); + up(&li->li_firstlock); + } + /* dlm_unlock() passes a 0 for castaddr which means don't overwrite the existing li_castaddr as that's the completion routine for unlocks. dlm_unlock_wait() specifies a new AST routine to be @@ -947,6 +957,7 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, if (!status && !convert_cancel) { spin_lock(&fi->fi_li_lock); list_del(&li->li_ownerqueue); + clear_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); } @@ -1055,7 +1066,7 @@ static int __init dlm_device_init(void) int r; INIT_LIST_HEAD(&user_ls_list); - init_MUTEX(&user_ls_lock); + mutex_init(&user_ls_lock); rwlock_init(&lockinfo_lock); ctl_device.name = "dlm-control"; diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 0f1dde54bcd279..46754553fdcc4a 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c @@ -33,7 +33,7 @@ static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de) static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) { - int found = FALSE; + int found = 0; struct dlm_direntry *de; spin_lock(&ls->ls_recover_list_lock); @@ -42,7 +42,7 @@ static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) list_del(&de->list); de->master_nodeid = 0; memset(de->name, 0, len); - found = TRUE; + found = 1; break; } } diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 0020cd07baf708..16f20cfd9197c9 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -42,20 +43,6 @@ #define DLM_LOCKSPACE_LEN 64 -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#if (BITS_PER_LONG == 64) -#define PRIx64 "lx" -#else -#define PRIx64 "Lx" -#endif - /* Size of the temp buffer midcomms allocates on the stack. We try to make this large enough so most messages fit. FIXME: should sctp make this unnecessary? */ @@ -266,7 +253,7 @@ struct dlm_lkb { struct dlm_rsb { struct dlm_ls *res_ls; /* the lockspace */ struct kref res_ref; - struct semaphore res_sem; + struct mutex res_mutex; unsigned long res_flags; int res_length; /* length of rsb name */ int res_nodeid; @@ -449,7 +436,7 @@ struct dlm_ls { struct dlm_dirtable *ls_dirtbl; uint32_t ls_dirtbl_size; - struct semaphore ls_waiters_sem; + struct mutex ls_waiters_mutex; struct list_head ls_waiters; /* lkbs needing a reply */ struct list_head ls_nodes; /* current nodes in ls */ @@ -472,14 +459,14 @@ struct dlm_ls { struct timer_list ls_timer; struct task_struct *ls_recoverd_task; - struct semaphore ls_recoverd_active; + struct mutex ls_recoverd_active; spinlock_t ls_recover_lock; uint32_t ls_recover_status; /* DLM_RS_ */ uint64_t ls_recover_seq; struct dlm_recover *ls_recover_args; struct rw_semaphore ls_in_recovery; /* block local requests */ struct list_head ls_requestqueue;/* queue remote requests */ - struct semaphore ls_requestqueue_lock; + struct mutex ls_requestqueue_mutex; char *ls_recover_buf; struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 81efb361f95df9..29d3b95dbb6369 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -215,15 +215,15 @@ static inline int is_master_copy(struct dlm_lkb *lkb) { if (lkb->lkb_flags & DLM_IFL_MSTCPY) DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb);); - return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? TRUE : FALSE; + return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0; } static inline int middle_conversion(struct dlm_lkb *lkb) { if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) || (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW)) - return TRUE; - return FALSE; + return 1; + return 0; } static inline int down_conversion(struct dlm_lkb *lkb) @@ -269,7 +269,7 @@ static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len) r->res_ls = ls; r->res_length = len; memcpy(r->res_name, name, len); - init_MUTEX(&r->res_sem); + mutex_init(&r->res_mutex); INIT_LIST_HEAD(&r->res_lookup); INIT_LIST_HEAD(&r->res_grantqueue); @@ -712,7 +712,7 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype) { struct dlm_ls *ls = lkb->lkb_resource->res_ls; - down(&ls->ls_waiters_sem); + mutex_lock(&ls->ls_waiters_mutex); if (lkb->lkb_wait_type) { log_print("add_to_waiters error %d", lkb->lkb_wait_type); goto out; @@ -721,7 +721,7 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype) kref_get(&lkb->lkb_ref); list_add(&lkb->lkb_wait_reply, &ls->ls_waiters); out: - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); } static int _remove_from_waiters(struct dlm_lkb *lkb) @@ -745,9 +745,9 @@ static int remove_from_waiters(struct dlm_lkb *lkb) struct dlm_ls *ls = lkb->lkb_resource->res_ls; int error; - down(&ls->ls_waiters_sem); + mutex_lock(&ls->ls_waiters_mutex); error = _remove_from_waiters(lkb); - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); return error; } @@ -775,14 +775,14 @@ static int shrink_bucket(struct dlm_ls *ls, int b) int count = 0, found; for (;;) { - found = FALSE; + found = 0; write_lock(&ls->ls_rsbtbl[b].lock); list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss, res_hashchain) { if (!time_after_eq(jiffies, r->res_toss_time + dlm_config.toss_secs * HZ)) continue; - found = TRUE; + found = 1; break; } @@ -1027,9 +1027,9 @@ static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb, lkb_statequeue); if (lkb->lkb_id == first->lkb_id) - return TRUE; + return 1; - return FALSE; + return 0; } /* Return 1 if the locks' ranges overlap. If the lkb has no range then it is @@ -1038,13 +1038,13 @@ static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2) { if (!lkb1->lkb_range || !lkb2->lkb_range) - return TRUE; + return 1; if (lkb1->lkb_range[RQ_RANGE_END] < lkb2->lkb_range[GR_RANGE_START] || lkb1->lkb_range[RQ_RANGE_START] > lkb2->lkb_range[GR_RANGE_END]) - return FALSE; + return 0; - return TRUE; + return 1; } /* Check if the given lkb conflicts with another lkb on the queue. */ @@ -1057,9 +1057,9 @@ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) if (this == lkb) continue; if (ranges_overlap(lkb, this) && !modes_compat(this, lkb)) - return TRUE; + return 1; } - return FALSE; + return 0; } /* @@ -1103,7 +1103,7 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) continue; if (!modes_compat(this, lkb) && !modes_compat(lkb, this)) - return TRUE; + return 1; } /* if lkb is on the convert queue and is preventing the first @@ -1114,10 +1114,10 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) if (self && self != first) { if (!modes_compat(lkb, first) && !queue_conflict(&rsb->res_grantqueue, first)) - return TRUE; + return 1; } - return FALSE; + return 0; } /* @@ -1157,7 +1157,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (lkb->lkb_exflags & DLM_LKF_EXPEDITE) - return TRUE; + return 1; /* * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be @@ -1200,7 +1200,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT)) - return TRUE; + return 1; /* * When using range locks the NOORDER flag is set to avoid the standard @@ -1208,7 +1208,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (lkb->lkb_exflags & DLM_LKF_NOORDER) - return TRUE; + return 1; /* * 6-3: Once in that queue [CONVERTING], a conversion request cannot be @@ -1217,7 +1217,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (!now && conv && first_in_list(lkb, &r->res_convertqueue)) - return TRUE; + return 1; /* * 6-4: By default, a new request is immediately granted only if all @@ -1232,7 +1232,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) if (now && !conv && list_empty(&r->res_convertqueue) && list_empty(&r->res_waitqueue)) - return TRUE; + return 1; /* * 6-4: Once a lock request is in the queue of ungranted new requests, @@ -1244,7 +1244,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) if (!now && !conv && list_empty(&r->res_convertqueue) && first_in_list(lkb, &r->res_waitqueue)) - return TRUE; + return 1; out: /* @@ -1257,7 +1257,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) lkb->lkb_sbflags |= DLM_SBF_DEMOTED; } - return FALSE; + return 0; } /* @@ -1308,7 +1308,7 @@ static int grant_pending_convert(struct dlm_rsb *r, int high) list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) { demoted = is_demoted(lkb); - if (can_be_granted(r, lkb, FALSE)) { + if (can_be_granted(r, lkb, 0)) { grant_lock_pending(r, lkb); grant_restart = 1; } else { @@ -1333,7 +1333,7 @@ static int grant_pending_wait(struct dlm_rsb *r, int high) struct dlm_lkb *lkb, *s; list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) { - if (can_be_granted(r, lkb, FALSE)) + if (can_be_granted(r, lkb, 0)) grant_lock_pending(r, lkb); else high = max_t(int, lkb->lkb_rqmode, high); @@ -1705,7 +1705,7 @@ static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb) { int error = 0; - if (can_be_granted(r, lkb, TRUE)) { + if (can_be_granted(r, lkb, 1)) { grant_lock(r, lkb); queue_cast(r, lkb, 0); goto out; @@ -1733,7 +1733,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) /* changing an existing lock may allow others to be granted */ - if (can_be_granted(r, lkb, TRUE)) { + if (can_be_granted(r, lkb, 1)) { grant_lock(r, lkb); queue_cast(r, lkb, 0); grant_pending_locks(r); @@ -2556,7 +2556,7 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms) { struct dlm_lkb *lkb; struct dlm_rsb *r; - int error, reply = TRUE; + int error, reply = 1; error = find_lkb(ls, ms->m_remid, &lkb); if (error) @@ -3205,7 +3205,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) { struct dlm_lkb *lkb, *safe; - down(&ls->ls_waiters_sem); + mutex_lock(&ls->ls_waiters_mutex); list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) { log_debug(ls, "pre recover waiter lkid %x type %d flags %x", @@ -3253,7 +3253,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) lkb->lkb_wait_type); } } - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); } static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) @@ -3261,7 +3261,7 @@ static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) struct dlm_lkb *lkb; int rv = 0; - down(&ls->ls_waiters_sem); + mutex_lock(&ls->ls_waiters_mutex); list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { if (lkb->lkb_flags & DLM_IFL_RESEND) { rv = lkb->lkb_wait_type; @@ -3270,7 +3270,7 @@ static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) break; } } - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); if (!rv) lkb = NULL; diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 9e6499f773da77..bffab9c88b1daf 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -38,12 +38,12 @@ static inline int is_master(struct dlm_rsb *r) static inline void lock_rsb(struct dlm_rsb *r) { - down(&r->res_sem); + mutex_lock(&r->res_mutex); } static inline void unlock_rsb(struct dlm_rsb *r) { - up(&r->res_sem); + mutex_unlock(&r->res_mutex); } #endif diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index fee4659b6582f2..d2ff505d51cd45 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -31,7 +31,7 @@ static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } #endif static int ls_count; -static struct semaphore ls_lock; +static struct mutex ls_lock; static struct list_head lslist; static spinlock_t lslist_lock; static struct task_struct * scand_task; @@ -177,7 +177,7 @@ int dlm_lockspace_init(void) int error; ls_count = 0; - init_MUTEX(&ls_lock); + mutex_init(&ls_lock); INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); @@ -351,10 +351,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, return -EEXIST; } - ls = kmalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); + ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); if (!ls) goto out; - memset(ls, 0, sizeof(struct dlm_ls) + namelen); memcpy(ls->ls_name, name, namelen); ls->ls_namelen = namelen; ls->ls_exflags = flags; @@ -398,7 +397,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, } INIT_LIST_HEAD(&ls->ls_waiters); - init_MUTEX(&ls->ls_waiters_sem); + mutex_init(&ls->ls_waiters_mutex); INIT_LIST_HEAD(&ls->ls_nodes); INIT_LIST_HEAD(&ls->ls_nodes_gone); @@ -416,14 +415,14 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_uevent_result = 0; ls->ls_recoverd_task = NULL; - init_MUTEX(&ls->ls_recoverd_active); + mutex_init(&ls->ls_recoverd_active); spin_lock_init(&ls->ls_recover_lock); ls->ls_recover_status = 0; ls->ls_recover_seq = 0; ls->ls_recover_args = NULL; init_rwsem(&ls->ls_in_recovery); INIT_LIST_HEAD(&ls->ls_requestqueue); - init_MUTEX(&ls->ls_requestqueue_lock); + mutex_init(&ls->ls_requestqueue_mutex); ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); if (!ls->ls_recover_buf) @@ -493,7 +492,7 @@ int dlm_new_lockspace(char *name, int namelen, void **lockspace, { int error = 0; - down(&ls_lock); + mutex_lock(&ls_lock); if (!ls_count) error = threads_start(); if (error) @@ -503,7 +502,7 @@ int dlm_new_lockspace(char *name, int namelen, void **lockspace, if (!error) ls_count++; out: - up(&ls_lock); + mutex_unlock(&ls_lock); return error; } @@ -629,11 +628,11 @@ static int release_lockspace(struct dlm_ls *ls, int force) kobject_unregister(&ls->ls_kobj); kfree(ls); - down(&ls_lock); + mutex_lock(&ls_lock); ls_count--; if (!ls_count) threads_stop(); - up(&ls_lock); + mutex_unlock(&ls_lock); module_put(THIS_MODULE); return 0; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 439249b62a574a..926cd0cb6bffff 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -52,7 +52,7 @@ static int dlm_add_member(struct dlm_ls *ls, int nodeid) struct dlm_member *memb; int w; - memb = kmalloc(sizeof(struct dlm_member), GFP_KERNEL); + memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); if (!memb) return -ENOMEM; @@ -79,9 +79,9 @@ static int dlm_is_member(struct dlm_ls *ls, int nodeid) list_for_each_entry(memb, &ls->ls_nodes, list) { if (memb->nodeid == nodeid) - return TRUE; + return 1; } - return FALSE; + return 0; } int dlm_is_removed(struct dlm_ls *ls, int nodeid) @@ -90,9 +90,9 @@ int dlm_is_removed(struct dlm_ls *ls, int nodeid) list_for_each_entry(memb, &ls->ls_nodes_gone, list) { if (memb->nodeid == nodeid) - return TRUE; + return 1; } - return FALSE; + return 0; } static void clear_memb_list(struct list_head *head) @@ -178,10 +178,10 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) /* move departed members from ls_nodes to ls_nodes_gone */ list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { - found = FALSE; + found = 0; for (i = 0; i < rv->node_count; i++) { if (memb->nodeid == rv->nodeids[i]) { - found = TRUE; + found = 1; break; } } @@ -271,10 +271,9 @@ int dlm_ls_start(struct dlm_ls *ls) int *ids = NULL; int error, count; - rv = kmalloc(sizeof(struct dlm_recover), GFP_KERNEL); + rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL); if (!rv) return -ENOMEM; - memset(rv, 0, sizeof(struct dlm_recover)); error = count = dlm_nodeid_list(ls->ls_name, &ids); if (error <= 0) diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index d96f9bbb407c4f..c9b1c3d535f4c0 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -119,7 +119,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, switch (msg->h_cmd) { case DLM_MSG: - dlm_receive_message(msg, nodeid, FALSE); + dlm_receive_message(msg, nodeid, 0); break; case DLM_RCOM: diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index 1712c97bc22937..b036ee7dcb32ae 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -420,7 +420,7 @@ int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc) r = recover_list_find(ls, rc->rc_id); if (!r) { - log_error(ls, "dlm_recover_master_reply no id %"PRIx64"", + log_error(ls, "dlm_recover_master_reply no id %llx", rc->rc_id); goto out; } @@ -477,8 +477,8 @@ static int all_queues_empty(struct dlm_rsb *r) if (!list_empty(&r->res_grantqueue) || !list_empty(&r->res_convertqueue) || !list_empty(&r->res_waitqueue)) - return FALSE; - return TRUE; + return 0; + return 1; } static int recover_locks(struct dlm_rsb *r) @@ -586,18 +586,18 @@ static void recover_lvb(struct dlm_rsb *r) { struct dlm_lkb *lkb, *high_lkb = NULL; uint32_t high_seq = 0; - int lock_lvb_exists = FALSE; - int big_lock_exists = FALSE; + int lock_lvb_exists = 0; + int big_lock_exists = 0; int lvblen = r->res_ls->ls_lvblen; list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) continue; - lock_lvb_exists = TRUE; + lock_lvb_exists = 1; if (lkb->lkb_grmode > DLM_LOCK_CR) { - big_lock_exists = TRUE; + big_lock_exists = 1; goto setflag; } @@ -611,10 +611,10 @@ static void recover_lvb(struct dlm_rsb *r) if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) continue; - lock_lvb_exists = TRUE; + lock_lvb_exists = 1; if (lkb->lkb_grmode > DLM_LOCK_CR) { - big_lock_exists = TRUE; + big_lock_exists = 1; goto setflag; } diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 06e4f7cab6e774..70103533677d91 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -45,9 +45,9 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) unsigned long start; int error, neg = 0; - log_debug(ls, "recover %"PRIx64"", rv->seq); + log_debug(ls, "recover %llx", rv->seq); - down(&ls->ls_recoverd_active); + mutex_lock(&ls->ls_recoverd_active); /* * Suspending and resuming dlm_astd ensures that no lkb's from this ls @@ -199,16 +199,16 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) dlm_astd_wake(); - log_debug(ls, "recover %"PRIx64" done: %u ms", rv->seq, + log_debug(ls, "recover %llx done: %u ms", rv->seq, jiffies_to_msecs(jiffies - start)); - up(&ls->ls_recoverd_active); + mutex_unlock(&ls->ls_recoverd_active); return 0; fail: dlm_release_root_list(ls); - log_debug(ls, "recover %"PRIx64" error %d", rv->seq, error); - up(&ls->ls_recoverd_active); + log_debug(ls, "recover %llx error %d", rv->seq, error); + mutex_unlock(&ls->ls_recoverd_active); return error; } @@ -275,11 +275,11 @@ void dlm_recoverd_stop(struct dlm_ls *ls) void dlm_recoverd_suspend(struct dlm_ls *ls) { - down(&ls->ls_recoverd_active); + mutex_lock(&ls->ls_recoverd_active); } void dlm_recoverd_resume(struct dlm_ls *ls) { - up(&ls->ls_recoverd_active); + mutex_unlock(&ls->ls_recoverd_active); } diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index 36afe99e4f93e1..7b2b089634a2df 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -47,9 +47,9 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) e->nodeid = nodeid; memcpy(e->request, hd, length); - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_add_tail(&e->list, &ls->ls_requestqueue); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } int dlm_process_requestqueue(struct dlm_ls *ls) @@ -58,19 +58,19 @@ int dlm_process_requestqueue(struct dlm_ls *ls) struct dlm_header *hd; int error = 0; - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); for (;;) { if (list_empty(&ls->ls_requestqueue)) { - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); error = 0; break; } e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); hd = (struct dlm_header *) e->request; - error = dlm_receive_message(hd, e->nodeid, TRUE); + error = dlm_receive_message(hd, e->nodeid, 1); if (error == -EINTR) { /* entry is left on requestqueue */ @@ -78,13 +78,13 @@ int dlm_process_requestqueue(struct dlm_ls *ls) break; } - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_del(&e->list); kfree(e); if (dlm_locking_stopped(ls)) { log_debug(ls, "process_requestqueue abort running"); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); error = -EINTR; break; } @@ -105,15 +105,15 @@ int dlm_process_requestqueue(struct dlm_ls *ls) void dlm_wait_requestqueue(struct dlm_ls *ls) { for (;;) { - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); if (list_empty(&ls->ls_requestqueue)) break; if (dlm_locking_stopped(ls)) break; - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); schedule(); } - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) @@ -170,7 +170,7 @@ void dlm_purge_requestqueue(struct dlm_ls *ls) struct dlm_message *ms; struct rq_entry *e, *safe; - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) { ms = (struct dlm_message *) e->request; @@ -179,6 +179,6 @@ void dlm_purge_requestqueue(struct dlm_ls *ls) kfree(e); } } - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } -- cgit 1.2.3-korg From 3bcd3687f895f178fa8480a7bcc47a363817354a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 09:56:38 +0000 Subject: [DLM] Remove range locks from the DLM This patch removes support for range locking from the DLM Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 14 ------ fs/dlm/device.c | 6 +-- fs/dlm/dlm_internal.h | 12 ------ fs/dlm/lock.c | 103 ++++----------------------------------------- fs/dlm/memory.c | 16 ------- fs/dlm/memory.h | 2 - fs/dlm/rcom.c | 3 -- fs/dlm/util.c | 12 ------ include/linux/dlm.h | 12 +----- include/linux/dlm_device.h | 3 +- 10 files changed, 13 insertions(+), 170 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 5080bbffd586a7..49deca845dbaf6 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -59,20 +59,6 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, || 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, " %llx-%llx", - 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, " (%llx-%llx)", - 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, diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 899d4f92a4d714..99d8b6b07fbafc 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -532,8 +532,7 @@ static int dlm_close(struct inode *inode, struct file *file) status = dlm_lock(f->fi_ls->ls_lockspace, old_li->li_grmode, &li.li_lksb, DLM_LKF_CONVERT|DLM_LKF_ORPHAN, - NULL, 0, 0, ast_routine, NULL, - NULL, NULL); + NULL, 0, 0, ast_routine, NULL, NULL); if (status != 0) printk("dlm: Error orphaning lock %x: %d\n", old_li->li_lksb.sb_lkid, status); @@ -878,8 +877,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, ast_routine, li, (li->li_pend_bastaddr || li->li_bastaddr) ? - bast_routine : NULL, - kparams->range.ra_end ? &kparams->range : NULL); + bast_routine : NULL); if (status) goto out_err; diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 16f20cfd9197c9..c3299020c8f318 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -146,7 +146,6 @@ struct dlm_args { void *bastaddr; int mode; struct dlm_lksb *lksb; - struct dlm_range *range; }; @@ -195,13 +194,6 @@ struct dlm_args { #define AST_COMP 1 #define AST_BAST 2 -/* lkb_range[] */ - -#define GR_RANGE_START 0 -#define GR_RANGE_END 1 -#define RQ_RANGE_START 2 -#define RQ_RANGE_END 3 - /* lkb_status */ #define DLM_LKSTS_WAITING 1 @@ -212,7 +204,6 @@ struct dlm_args { #define DLM_IFL_MSTCPY 0x00010000 #define DLM_IFL_RESEND 0x00020000 -#define DLM_IFL_RANGE 0x00000001 struct dlm_lkb { struct dlm_rsb *lkb_resource; /* the rsb */ @@ -241,7 +232,6 @@ struct dlm_lkb { struct list_head lkb_wait_reply; /* waiting for remote reply */ struct list_head lkb_astqueue; /* need ast to be sent */ - uint64_t *lkb_range; /* array of gr/rq ranges */ char *lkb_lvbptr; struct dlm_lksb *lkb_lksb; /* caller's status block */ void *lkb_astaddr; /* caller's ast function */ @@ -360,7 +350,6 @@ struct dlm_message { int m_bastmode; int m_asts; int m_result; /* 0 or -EXXX */ - uint64_t m_range[2]; char m_extra[0]; /* name or lvb */ }; @@ -413,7 +402,6 @@ struct rcom_lock { int8_t rl_asts; uint16_t rl_wait_type; uint16_t rl_namelen; - uint64_t rl_range[4]; char rl_name[DLM_RESNAME_MAXLEN]; char rl_lvb[0]; }; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 29d3b95dbb6369..80487703d58210 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -606,8 +606,6 @@ static int put_lkb(struct dlm_lkb *lkb) /* for local/process lkbs, lvbptr points to caller's lksb */ if (lkb->lkb_lvbptr && is_master_copy(lkb)) free_lvb(lkb->lkb_lvbptr); - if (lkb->lkb_range) - free_range(lkb->lkb_range); free_lkb(lkb); return 1; } else { @@ -988,11 +986,6 @@ static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) } lkb->lkb_rqmode = DLM_LOCK_IV; - - if (lkb->lkb_range) { - lkb->lkb_range[GR_RANGE_START] = lkb->lkb_range[RQ_RANGE_START]; - lkb->lkb_range[GR_RANGE_END] = lkb->lkb_range[RQ_RANGE_END]; - } } static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) @@ -1032,21 +1025,6 @@ static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) return 0; } -/* Return 1 if the locks' ranges overlap. If the lkb has no range then it is - assumed to cover 0-ffffffff.ffffffff */ - -static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2) -{ - if (!lkb1->lkb_range || !lkb2->lkb_range) - return 1; - - if (lkb1->lkb_range[RQ_RANGE_END] < lkb2->lkb_range[GR_RANGE_START] || - lkb1->lkb_range[RQ_RANGE_START] > lkb2->lkb_range[GR_RANGE_END]) - return 0; - - return 1; -} - /* Check if the given lkb conflicts with another lkb on the queue. */ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) @@ -1056,7 +1034,7 @@ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) list_for_each_entry(this, head, lkb_statequeue) { if (this == lkb) continue; - if (ranges_overlap(lkb, this) && !modes_compat(this, lkb)) + if (!modes_compat(this, lkb)) return 1; } return 0; @@ -1099,9 +1077,6 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) continue; } - if (!ranges_overlap(lkb, this)) - continue; - if (!modes_compat(this, lkb) && !modes_compat(lkb, this)) return 1; } @@ -1203,8 +1178,8 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) return 1; /* - * When using range locks the NOORDER flag is set to avoid the standard - * vms rules on grant order. + * The NOORDER flag is set to avoid the standard vms rules on grant + * order. */ if (lkb->lkb_exflags & DLM_LKF_NOORDER) @@ -1358,8 +1333,7 @@ static void grant_pending_locks(struct dlm_rsb *r) /* * If there are locks left on the wait/convert queue then send blocking * ASTs to granted locks based on the largest requested mode (high) - * found above. This can generate spurious blocking ASTs for range - * locks. FIXME: highbast < high comparison not valid for PR/CW. + * found above. FIXME: highbast < high comparison not valid for PR/CW. */ list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { @@ -1379,7 +1353,7 @@ static void send_bast_queue(struct dlm_rsb *r, struct list_head *head, list_for_each_entry(gr, head, lkb_statequeue) { if (gr->lkb_bastaddr && gr->lkb_highbast < lkb->lkb_rqmode && - ranges_overlap(lkb, gr) && !modes_compat(gr, lkb)) { + !modes_compat(gr, lkb)) { queue_bast(r, gr, lkb->lkb_rqmode); gr->lkb_highbast = lkb->lkb_rqmode; } @@ -1530,8 +1504,7 @@ static void confirm_master(struct dlm_rsb *r, int error) static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags, int namelen, uint32_t parent_lkid, void *ast, - void *astarg, void *bast, struct dlm_range *range, - struct dlm_args *args) + void *astarg, void *bast, struct dlm_args *args) { int rv = -EINVAL; @@ -1590,7 +1563,6 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags, args->bastaddr = bast; args->mode = mode; args->lksb = lksb; - args->range = range; rv = 0; out: return rv; @@ -1637,26 +1609,6 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, lkb->lkb_lksb = args->lksb; lkb->lkb_lvbptr = args->lksb->sb_lvbptr; lkb->lkb_ownpid = (int) current->pid; - - rv = 0; - if (!args->range) - goto out; - - if (!lkb->lkb_range) { - rv = -ENOMEM; - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - goto out; - /* This is needed for conversions that contain ranges - where the original lock didn't but it's harmless for - new locks too. */ - lkb->lkb_range[GR_RANGE_START] = 0LL; - lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; - } - - lkb->lkb_range[RQ_RANGE_START] = args->range->ra_start; - lkb->lkb_range[RQ_RANGE_END] = args->range->ra_end; - lkb->lkb_flags |= DLM_IFL_RANGE; rv = 0; out: return rv; @@ -1805,7 +1757,7 @@ static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) return error; } -/* change some property of an existing lkb, e.g. mode, range */ +/* change some property of an existing lkb, e.g. mode */ static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) { @@ -1962,8 +1914,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, uint32_t parent_lkid, void (*ast) (void *astarg), void *astarg, - void (*bast) (void *astarg, int mode), - struct dlm_range *range) + void (*bast) (void *astarg, int mode)) { struct dlm_ls *ls; struct dlm_lkb *lkb; @@ -1985,7 +1936,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, goto out; error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast, - astarg, bast, range, &args); + astarg, bast, &args); if (error) goto out_put; @@ -2154,11 +2105,6 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb, if (lkb->lkb_astaddr) ms->m_asts |= AST_COMP; - if (lkb->lkb_range) { - ms->m_range[0] = lkb->lkb_range[RQ_RANGE_START]; - ms->m_range[1] = lkb->lkb_range[RQ_RANGE_END]; - } - if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP) memcpy(ms->m_extra, r->res_name, r->res_length); @@ -2402,20 +2348,6 @@ static int receive_extralen(struct dlm_message *ms) return (ms->m_header.h_length - sizeof(struct dlm_message)); } -static int receive_range(struct dlm_ls *ls, struct dlm_lkb *lkb, - struct dlm_message *ms) -{ - if (lkb->lkb_flags & DLM_IFL_RANGE) { - if (!lkb->lkb_range) - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - return -ENOMEM; - lkb->lkb_range[RQ_RANGE_START] = ms->m_range[0]; - lkb->lkb_range[RQ_RANGE_END] = ms->m_range[1]; - } - return 0; -} - static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_message *ms) { @@ -2445,9 +2377,6 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb);); - if (receive_range(ls, lkb, ms)) - return -ENOMEM; - if (receive_lvb(ls, lkb, ms)) return -ENOMEM; @@ -2470,13 +2399,6 @@ static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, if (lkb->lkb_status != DLM_LKSTS_GRANTED) return -EBUSY; - if (receive_range(ls, lkb, ms)) - return -ENOMEM; - if (lkb->lkb_range) { - lkb->lkb_range[GR_RANGE_START] = 0LL; - lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; - } - if (receive_lvb(ls, lkb, ms)) return -ENOMEM; @@ -3476,13 +3398,6 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST); lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP); - if (lkb->lkb_flags & DLM_IFL_RANGE) { - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - return -ENOMEM; - memcpy(lkb->lkb_range, rl->rl_range, 4*sizeof(uint64_t)); - } - if (lkb->lkb_exflags & DLM_LKF_VALBLK) { lkb->lkb_lvbptr = allocate_lvb(ls); if (!lkb->lkb_lvbptr) diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index 0b9851d0bdb2d9..f7cf4589fae8fc 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -50,22 +50,6 @@ void free_lvb(char *p) kfree(p); } -uint64_t *allocate_range(struct dlm_ls *ls) -{ - int ralen = 4*sizeof(uint64_t); - uint64_t *p; - - p = kmalloc(ralen, GFP_KERNEL); - if (p) - memset(p, 0, ralen); - return p; -} - -void free_range(uint64_t *p) -{ - kfree(p); -} - /* FIXME: have some minimal space built-in to rsb for the name and kmalloc a separate name if needed, like dentries are done */ diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h index 7b235132b0b437..6ead158ccc5c66 100644 --- a/fs/dlm/memory.h +++ b/fs/dlm/memory.h @@ -24,8 +24,6 @@ struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen); void free_direntry(struct dlm_direntry *de); char *allocate_lvb(struct dlm_ls *ls); void free_lvb(char *l); -uint64_t *allocate_range(struct dlm_ls *ls); -void free_range(uint64_t *l); #endif /* __MEMORY_DOT_H__ */ diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 4c5c08a8860e92..55fbe313340e59 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -284,9 +284,6 @@ static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb, if (lkb->lkb_astaddr) rl->rl_asts |= AST_COMP; - if (lkb->lkb_range) - memcpy(rl->rl_range, lkb->lkb_range, 4*sizeof(uint64_t)); - rl->rl_namelen = r->res_length; memcpy(rl->rl_name, r->res_name, r->res_length); diff --git a/fs/dlm/util.c b/fs/dlm/util.c index 826d122edf559b..767197db994404 100644 --- a/fs/dlm/util.c +++ b/fs/dlm/util.c @@ -54,8 +54,6 @@ void dlm_message_out(struct dlm_message *ms) ms->m_bastmode = cpu_to_le32(ms->m_bastmode); ms->m_asts = cpu_to_le32(ms->m_asts); ms->m_result = cpu_to_le32(ms->m_result); - ms->m_range[0] = cpu_to_le64(ms->m_range[0]); - ms->m_range[1] = cpu_to_le64(ms->m_range[1]); } void dlm_message_in(struct dlm_message *ms) @@ -82,8 +80,6 @@ void dlm_message_in(struct dlm_message *ms) ms->m_bastmode = le32_to_cpu(ms->m_bastmode); ms->m_asts = le32_to_cpu(ms->m_asts); ms->m_result = le32_to_cpu(ms->m_result); - ms->m_range[0] = le64_to_cpu(ms->m_range[0]); - ms->m_range[1] = le64_to_cpu(ms->m_range[1]); } static void rcom_lock_out(struct rcom_lock *rl) @@ -99,10 +95,6 @@ static void rcom_lock_out(struct rcom_lock *rl) rl->rl_result = cpu_to_le32(rl->rl_result); rl->rl_wait_type = cpu_to_le16(rl->rl_wait_type); rl->rl_namelen = cpu_to_le16(rl->rl_namelen); - rl->rl_range[0] = cpu_to_le64(rl->rl_range[0]); - rl->rl_range[1] = cpu_to_le64(rl->rl_range[1]); - rl->rl_range[2] = cpu_to_le64(rl->rl_range[2]); - rl->rl_range[3] = cpu_to_le64(rl->rl_range[3]); } static void rcom_lock_in(struct rcom_lock *rl) @@ -118,10 +110,6 @@ static void rcom_lock_in(struct rcom_lock *rl) rl->rl_result = le32_to_cpu(rl->rl_result); rl->rl_wait_type = le16_to_cpu(rl->rl_wait_type); rl->rl_namelen = le16_to_cpu(rl->rl_namelen); - rl->rl_range[0] = le64_to_cpu(rl->rl_range[0]); - rl->rl_range[1] = le64_to_cpu(rl->rl_range[1]); - rl->rl_range[2] = le64_to_cpu(rl->rl_range[2]); - rl->rl_range[3] = le64_to_cpu(rl->rl_range[3]); } static void rcom_config_out(struct rcom_config *rf) diff --git a/include/linux/dlm.h b/include/linux/dlm.h index dd324ba44d8004..1b1dcb9a40bbab 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -159,15 +159,6 @@ typedef void dlm_lockspace_t; -/* - * Lock range structure - */ - -struct dlm_range { - uint64_t ra_start; - uint64_t ra_end; -}; - /* * Lock status block * @@ -277,8 +268,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, uint32_t parent_lkid, void (*lockast) (void *astarg), void *astarg, - void (*bast) (void *astarg, int mode), - struct dlm_range *range); + void (*bast) (void *astarg, int mode)); /* * dlm_unlock diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h index 5e17d295544b3c..f8ba1981aa96cf 100644 --- a/include/linux/dlm_device.h +++ b/include/linux/dlm_device.h @@ -18,7 +18,7 @@ #define DLM_USER_LVB_LEN 32 /* Version of the device interface */ -#define DLM_DEVICE_VERSION_MAJOR 3 +#define DLM_DEVICE_VERSION_MAJOR 4 #define DLM_DEVICE_VERSION_MINOR 0 #define DLM_DEVICE_VERSION_PATCH 0 @@ -28,7 +28,6 @@ struct dlm_lock_params { __u16 flags; __u32 lkid; __u32 parent; - struct dlm_range range; __u8 namelen; void __user *castparam; void __user *castaddr; -- cgit 1.2.3-korg From 97a35d1e5fab9ff8de27814082b78b2fc9ad94f0 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 2 May 2006 13:34:03 -0400 Subject: [DLM] fix grant_after_purge softlockup In dlm_grant_after_purge() we were holding a hash table read_lock while calling put_rsb() which potentially removes the rsb from the hash table, taking the same lock in write. Fix this by flagging rsb's ahead of time that have been purged. Then iteratively read_lock the hash table, find a flagged rsb, unlock, process rsb. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/lock.c | 42 ++++++++++++++++++++++++++++-------------- fs/dlm/lock.h | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index c3299020c8f318..149106f2b80fab 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -280,6 +280,7 @@ enum rsb_flags { RSB_NEW_MASTER, RSB_NEW_MASTER2, RSB_RECOVER_CONVERT, + RSB_LOCKS_PURGED, }; static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 85a0e73ba808cf..5f69639041078f 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3278,6 +3278,7 @@ static void purge_queue(struct dlm_rsb *r, struct list_head *queue, list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) { if (test(ls, lkb)) { + rsb_set_flag(r, RSB_LOCKS_PURGED); del_lkb(r, lkb); /* this put should free the lkb */ if (!dlm_put_lkb(lkb)) @@ -3334,27 +3335,40 @@ int dlm_purge_locks(struct dlm_ls *ls) return 0; } -int dlm_grant_after_purge(struct dlm_ls *ls) +static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket) +{ + struct dlm_rsb *r, *r_ret = NULL; + + read_lock(&ls->ls_rsbtbl[bucket].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) { + if (!rsb_flag(r, RSB_LOCKS_PURGED)) + continue; + hold_rsb(r); + rsb_clear_flag(r, RSB_LOCKS_PURGED); + r_ret = r; + break; + } + read_unlock(&ls->ls_rsbtbl[bucket].lock); + return r_ret; +} + +void dlm_grant_after_purge(struct dlm_ls *ls) { struct dlm_rsb *r; int i; for (i = 0; i < ls->ls_rsbtbl_size; i++) { - read_lock(&ls->ls_rsbtbl[i].lock); - list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) { - hold_rsb(r); - lock_rsb(r); - if (is_master(r)) { - grant_pending_locks(r); - confirm_master(r, 0); - } - unlock_rsb(r); - put_rsb(r); + r = find_purged_rsb(ls, i); + if (!r) + continue; + lock_rsb(r); + if (is_master(r)) { + grant_pending_locks(r); + confirm_master(r, 0); } - read_unlock(&ls->ls_rsbtbl[i].lock); + unlock_rsb(r); + put_rsb(r); } - - return 0; } static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid, diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index bffab9c88b1daf..56cdc073b1f61b 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -25,7 +25,7 @@ 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); +void 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); -- cgit 1.2.3-korg From 597d0cae0f99f62501e229bed50e8149604015bb Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 12 Jul 2006 16:44:04 -0500 Subject: [DLM] dlm: user locks This changes the way the dlm handles user locks. The core dlm is now aware of user locks so they can be dealt with more efficiently. There is no more dlm_device module which previously managed its own duplicate copy of every user lock. Signed-off-by: Patrick Caulfield Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/Kconfig | 8 - fs/dlm/Makefile | 4 +- fs/dlm/ast.c | 7 +- fs/dlm/device.c | 1239 ------------------------------------------------- fs/dlm/dlm_internal.h | 44 ++ fs/dlm/lock.c | 304 +++++++++++- fs/dlm/lock.h | 11 + fs/dlm/lockspace.c | 32 +- fs/dlm/lockspace.h | 1 + fs/dlm/main.c | 8 + fs/dlm/memory.c | 9 + fs/dlm/user.c | 769 ++++++++++++++++++++++++++++++ fs/dlm/user.h | 16 + 13 files changed, 1192 insertions(+), 1260 deletions(-) delete mode 100644 fs/dlm/device.c create mode 100644 fs/dlm/user.c create mode 100644 fs/dlm/user.h (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index 09e78bf6e7a463..490f85b3fa590e 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -10,14 +10,6 @@ config DLM 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 diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile index 1e6232e7d8e5ca..1832e0297f7d82 100644 --- a/fs/dlm/Makefile +++ b/fs/dlm/Makefile @@ -1,6 +1,4 @@ obj-$(CONFIG_DLM) += dlm.o -obj-$(CONFIG_DLM_DEVICE) += dlm_device.o - dlm-y := ast.o \ config.o \ dir.o \ @@ -15,7 +13,7 @@ dlm-y := ast.o \ recover.o \ recoverd.o \ requestqueue.o \ + user.o \ util.o dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o -dlm_device-y := device.o diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 57bdf09b520a8a..a211330cbc422e 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -13,7 +13,7 @@ #include "dlm_internal.h" #include "lock.h" -#include "ast.h" +#include "user.h" #define WAKE_ASTS 0 @@ -34,6 +34,11 @@ void dlm_del_ast(struct dlm_lkb *lkb) void dlm_add_ast(struct dlm_lkb *lkb, int type) { + if (lkb->lkb_flags & DLM_IFL_USER) { + dlm_user_add_ast(lkb, type); + return; + } + spin_lock(&ast_queue_lock); if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { kref_get(&lkb->lkb_ref); diff --git a/fs/dlm/device.c b/fs/dlm/device.c deleted file mode 100644 index 825bbc0a09c083..00000000000000 --- a/fs/dlm/device.c +++ /dev/null @@ -1,1239 +0,0 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2006 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. -** -******************************************************************************* -******************************************************************************/ - -/* - * device.c - * - * This is the userland interface to the DLM. - * - * The locking is done via a misc char device (find the - * registered minor number in /proc/misc). - * - * User code should not use this interface directly but - * call the library routines in libdlm.a instead. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "lvb_table.h" - -static struct file_operations _dlm_fops; -static const char *name_prefix="dlm"; -static struct list_head user_ls_list; -static struct mutex user_ls_lock; - -/* Flags in li_flags */ -#define LI_FLAG_COMPLETE 1 -#define LI_FLAG_FIRSTLOCK 2 -#define LI_FLAG_PERSISTENT 3 -#define LI_FLAG_ONLIST 4 - -/* flags in ls_flags*/ -#define LS_FLAG_DELETED 1 -#define LS_FLAG_AUTOFREE 2 - -/* flags in ls_flags*/ -#define FI_FLAG_OPEN 1 -#define FI_FLAG_COMPAT 2 - -#define LOCKINFO_MAGIC 0x53595324 - -struct lock_info { - uint32_t li_magic; - uint8_t li_cmd; - int8_t li_grmode; - int8_t li_rqmode; - struct dlm_lksb li_lksb; - wait_queue_head_t li_waitq; - unsigned long li_flags; - void __user *li_castparam; - void __user *li_castaddr; - void __user *li_bastparam; - void __user *li_bastaddr; - void __user *li_pend_bastparam; - void __user *li_pend_bastaddr; - struct list_head li_ownerqueue; - struct file_info *li_file; - struct dlm_lksb __user *li_user_lksb; - struct completion li_firstcomp; -}; - -/* A queued AST no less */ -struct ast_info { - struct dlm_lock_result result; - struct list_head list; - uint32_t lvb_updated; - uint32_t progress; /* How much has been read */ -}; - -/* One of these per userland lockspace */ -struct user_ls { - void *ls_lockspace; - atomic_t ls_refcnt; - long ls_flags; - - /* Lock infos are stored in here indexed by lock ID */ - struct idr lockinfo_idr; - rwlock_t lockinfo_lock; - - /* Passed into misc_register() */ - struct miscdevice ls_miscinfo; - struct list_head ls_list; -}; - -/* misc_device info for the control device */ -static struct miscdevice ctl_device; - -/* - * Stuff we hang off the file struct. - * The first two are to cope with unlocking all the - * locks help by a process when it dies. - */ -struct file_info { - struct list_head fi_li_list; /* List of active lock_infos */ - spinlock_t fi_li_lock; - struct list_head fi_ast_list; /* Queue of ASTs to be delivered */ - spinlock_t fi_ast_lock; - wait_queue_head_t fi_wait; - struct user_ls *fi_ls; - atomic_t fi_refcnt; /* Number of users */ - unsigned long fi_flags; -}; - -#ifdef CONFIG_COMPAT - -struct dlm_lock_params32 { - __u8 mode; - __u8 namelen; - __u16 flags; - __u32 lkid; - __u32 parent; - - __u32 castparam; - __u32 castaddr; - __u32 bastparam; - __u32 bastaddr; - __u32 lksb; - - char lvb[DLM_USER_LVB_LEN]; - char name[0]; -}; - -struct dlm_write_request32 { - __u32 version[3]; - __u8 cmd; - __u8 is64bit; - __u8 unused[2]; - - union { - struct dlm_lock_params32 lock; - struct dlm_lspace_params lspace; - } i; -}; - -struct dlm_lksb32 { - __u32 sb_status; - __u32 sb_lkid; - __u8 sb_flags; - __u32 sb_lvbptr; -}; - -struct dlm_lock_result32 { - __u32 length; - __u32 user_astaddr; - __u32 user_astparam; - __u32 user_lksb; - struct dlm_lksb32 lksb; - __u8 bast_mode; - __u8 unused[3]; - /* Offsets may be zero if no data is present */ - __u32 lvb_offset; -}; - - -static void compat_input(struct dlm_write_request *kparams, struct dlm_write_request32 *k32params) -{ - - kparams->version[0] = k32params->version[0]; - kparams->version[1] = k32params->version[1]; - kparams->version[2] = k32params->version[2]; - - kparams->cmd = k32params->cmd; - kparams->is64bit = k32params->is64bit; - if (kparams->cmd == DLM_USER_CREATE_LOCKSPACE || - kparams->cmd == DLM_USER_REMOVE_LOCKSPACE) { - - kparams->i.lspace.flags = k32params->i.lspace.flags; - kparams->i.lspace.minor = k32params->i.lspace.minor; - strcpy(kparams->i.lspace.name, k32params->i.lspace.name); - } - else { - kparams->i.lock.mode = k32params->i.lock.mode; - kparams->i.lock.namelen = k32params->i.lock.namelen; - kparams->i.lock.flags = k32params->i.lock.flags; - kparams->i.lock.lkid = k32params->i.lock.lkid; - kparams->i.lock.parent = k32params->i.lock.parent; - kparams->i.lock.castparam = (void *)(long)k32params->i.lock.castparam; - kparams->i.lock.castaddr = (void *)(long)k32params->i.lock.castaddr; - kparams->i.lock.bastparam = (void *)(long)k32params->i.lock.bastparam; - kparams->i.lock.bastaddr = (void *)(long)k32params->i.lock.bastaddr; - kparams->i.lock.lksb = (void *)(long)k32params->i.lock.lksb; - memcpy(kparams->i.lock.lvb, k32params->i.lock.lvb, DLM_USER_LVB_LEN); - memcpy(kparams->i.lock.name, k32params->i.lock.name, kparams->i.lock.namelen); - } -} - -void compat_output(struct dlm_lock_result *res, struct dlm_lock_result32 *res32) -{ - res32->length = res->length - (sizeof(struct dlm_lock_result) - sizeof(struct dlm_lock_result32)); - res32->user_astaddr = (__u32)(long)res->user_astaddr; - res32->user_astparam = (__u32)(long)res->user_astparam; - res32->user_lksb = (__u32)(long)res->user_lksb; - res32->bast_mode = res->bast_mode; - - res32->lvb_offset = res->lvb_offset; - res32->length = res->length; - - res32->lksb.sb_status = res->lksb.sb_status; - res32->lksb.sb_flags = res->lksb.sb_flags; - res32->lksb.sb_lkid = res->lksb.sb_lkid; - res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; -} -#endif - - -/* get and put ops for file_info. - Actually I don't really like "get" and "put", but everyone - else seems to use them and I can't think of anything - nicer at the moment */ -static void get_file_info(struct file_info *f) -{ - atomic_inc(&f->fi_refcnt); -} - -static void put_file_info(struct file_info *f) -{ - if (atomic_dec_and_test(&f->fi_refcnt)) - kfree(f); -} - -static void release_lockinfo(struct user_ls *ls, struct lock_info *li) -{ - put_file_info(li->li_file); - - write_lock(&ls->lockinfo_lock); - idr_remove(&ls->lockinfo_idr, li->li_lksb.sb_lkid); - write_unlock(&ls->lockinfo_lock); - - if (li->li_lksb.sb_lvbptr) - kfree(li->li_lksb.sb_lvbptr); - kfree(li); - - module_put(THIS_MODULE); -} - -static struct lock_info *get_lockinfo(struct user_ls *ls, uint32_t lockid) -{ - struct lock_info *li; - - read_lock(&ls->lockinfo_lock); - li = idr_find(&ls->lockinfo_idr, lockid); - read_unlock(&ls->lockinfo_lock); - - return li; -} - -static int add_lockinfo(struct user_ls *ls, struct lock_info *li) -{ - int n; - int r; - int ret = -EINVAL; - - write_lock(&ls->lockinfo_lock); - - if (idr_find(&ls->lockinfo_idr, li->li_lksb.sb_lkid)) - goto out_up; - - ret = -ENOMEM; - r = idr_pre_get(&ls->lockinfo_idr, GFP_KERNEL); - if (!r) - goto out_up; - - r = idr_get_new_above(&ls->lockinfo_idr, li, li->li_lksb.sb_lkid, &n); - if (r) - goto out_up; - - if (n != li->li_lksb.sb_lkid) { - idr_remove(&ls->lockinfo_idr, n); - goto out_up; - } - - ret = 0; - - out_up: - write_unlock(&ls->lockinfo_lock); - - return ret; -} - - -static struct user_ls *__find_lockspace(int minor) -{ - struct user_ls *lsinfo; - - list_for_each_entry(lsinfo, &user_ls_list, ls_list) { - if (lsinfo->ls_miscinfo.minor == minor) - return lsinfo; - } - return NULL; -} - -/* Find a lockspace struct given the device minor number */ -static struct user_ls *find_lockspace(int minor) -{ - struct user_ls *lsinfo; - - mutex_lock(&user_ls_lock); - lsinfo = __find_lockspace(minor); - mutex_unlock(&user_ls_lock); - - return lsinfo; -} - -static void add_lockspace_to_list(struct user_ls *lsinfo) -{ - mutex_lock(&user_ls_lock); - list_add(&lsinfo->ls_list, &user_ls_list); - mutex_unlock(&user_ls_lock); -} - -/* Register a lockspace with the DLM and create a misc - device for userland to access it */ -static int register_lockspace(char *name, struct user_ls **ls, int flags) -{ - struct user_ls *newls; - int status; - int namelen; - - namelen = strlen(name)+strlen(name_prefix)+2; - - newls = kzalloc(sizeof(struct user_ls), GFP_KERNEL); - if (!newls) - return -ENOMEM; - - newls->ls_miscinfo.name = kzalloc(namelen, GFP_KERNEL); - if (!newls->ls_miscinfo.name) { - kfree(newls); - return -ENOMEM; - } - - status = dlm_new_lockspace(name, strlen(name), &newls->ls_lockspace, 0, - DLM_USER_LVB_LEN); - if (status != 0) { - kfree(newls->ls_miscinfo.name); - kfree(newls); - return status; - } - - idr_init(&newls->lockinfo_idr); - rwlock_init(&newls->lockinfo_lock); - - snprintf((char*)newls->ls_miscinfo.name, namelen, "%s_%s", - name_prefix, name); - - newls->ls_miscinfo.fops = &_dlm_fops; - newls->ls_miscinfo.minor = MISC_DYNAMIC_MINOR; - - status = misc_register(&newls->ls_miscinfo); - if (status) { - printk(KERN_ERR "dlm: misc register failed for %s\n", name); - dlm_release_lockspace(newls->ls_lockspace, 0); - kfree(newls->ls_miscinfo.name); - kfree(newls); - return status; - } - - if (flags & DLM_USER_LSFLG_AUTOFREE) - set_bit(LS_FLAG_AUTOFREE, &newls->ls_flags); - - add_lockspace_to_list(newls); - *ls = newls; - return 0; -} - -/* Called with the user_ls_lock mutex held */ -static int unregister_lockspace(struct user_ls *lsinfo, int force) -{ - int status; - - status = dlm_release_lockspace(lsinfo->ls_lockspace, force); - if (status) - return status; - - status = misc_deregister(&lsinfo->ls_miscinfo); - if (status) - return status; - - list_del(&lsinfo->ls_list); - set_bit(LS_FLAG_DELETED, &lsinfo->ls_flags); - lsinfo->ls_lockspace = NULL; - if (atomic_read(&lsinfo->ls_refcnt) == 0) { - kfree(lsinfo->ls_miscinfo.name); - kfree(lsinfo); - } - - return 0; -} - -/* Add it to userland's AST queue */ -static void add_to_astqueue(struct lock_info *li, void *astaddr, void *astparam, - int lvb_updated) -{ - struct ast_info *ast = kzalloc(sizeof(struct ast_info), GFP_KERNEL); - if (!ast) - return; - - ast->result.user_astparam = astparam; - ast->result.user_astaddr = astaddr; - ast->result.user_lksb = li->li_user_lksb; - memcpy(&ast->result.lksb, &li->li_lksb, sizeof(struct dlm_lksb)); - ast->lvb_updated = lvb_updated; - - spin_lock(&li->li_file->fi_ast_lock); - list_add_tail(&ast->list, &li->li_file->fi_ast_list); - spin_unlock(&li->li_file->fi_ast_lock); - wake_up_interruptible(&li->li_file->fi_wait); -} - -static void bast_routine(void *param, int mode) -{ - struct lock_info *li = param; - - if (li && li->li_bastaddr) - add_to_astqueue(li, li->li_bastaddr, li->li_bastparam, 0); -} - -/* - * This is the kernel's AST routine. - * All lock, unlock & query operations complete here. - * The only syncronous ops are those done during device close. - */ -static void ast_routine(void *param) -{ - struct lock_info *li = param; - - /* Param may be NULL if a persistent lock is unlocked by someone else */ - if (!li) - return; - - /* If this is a succesful conversion then activate the blocking ast - * args from the conversion request */ - if (!test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) && - li->li_lksb.sb_status == 0) { - - li->li_bastparam = li->li_pend_bastparam; - li->li_bastaddr = li->li_pend_bastaddr; - li->li_pend_bastaddr = NULL; - } - - /* If it's an async request then post data to the user's AST queue. */ - if (li->li_castaddr) { - int lvb_updated = 0; - - /* See if the lvb has been updated */ - if (dlm_lvb_operations[li->li_grmode+1][li->li_rqmode+1] == 1) - lvb_updated = 1; - - if (li->li_lksb.sb_status == 0) - li->li_grmode = li->li_rqmode; - - /* Only queue AST if the device is still open */ - if (test_bit(FI_FLAG_OPEN, &li->li_file->fi_flags)) - add_to_astqueue(li, li->li_castaddr, li->li_castparam, - lvb_updated); - - /* If it's a new lock operation that failed, then - * remove it from the owner queue and free the - * lock_info. - */ - if (test_and_clear_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) && - li->li_lksb.sb_status != 0) { - - /* Wait till dlm_lock() has finished */ - wait_for_completion(&li->li_firstcomp); - - spin_lock(&li->li_file->fi_li_lock); - list_del(&li->li_ownerqueue); - clear_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&li->li_file->fi_li_lock); - release_lockinfo(li->li_file->fi_ls, li); - return; - } - /* Free unlocks & queries */ - if (li->li_lksb.sb_status == -DLM_EUNLOCK || - li->li_cmd == DLM_USER_QUERY) { - release_lockinfo(li->li_file->fi_ls, li); - } - } else { - /* Synchronous request, just wake up the caller */ - set_bit(LI_FLAG_COMPLETE, &li->li_flags); - wake_up_interruptible(&li->li_waitq); - } -} - -/* - * Wait for the lock op to complete and return the status. - */ -static int wait_for_ast(struct lock_info *li) -{ - /* Wait for the AST routine to complete */ - set_task_state(current, TASK_INTERRUPTIBLE); - while (!test_bit(LI_FLAG_COMPLETE, &li->li_flags)) - schedule(); - - set_task_state(current, TASK_RUNNING); - - return li->li_lksb.sb_status; -} - - -/* Open on control device */ -static int dlm_ctl_open(struct inode *inode, struct file *file) -{ - file->private_data = NULL; - return 0; -} - -/* Close on control device */ -static int dlm_ctl_close(struct inode *inode, struct file *file) -{ - return 0; -} - -/* Open on lockspace device */ -static int dlm_open(struct inode *inode, struct file *file) -{ - struct file_info *f; - struct user_ls *lsinfo; - - lsinfo = find_lockspace(iminor(inode)); - if (!lsinfo) - return -ENOENT; - - f = kzalloc(sizeof(struct file_info), GFP_KERNEL); - if (!f) - return -ENOMEM; - - atomic_inc(&lsinfo->ls_refcnt); - INIT_LIST_HEAD(&f->fi_li_list); - INIT_LIST_HEAD(&f->fi_ast_list); - spin_lock_init(&f->fi_li_lock); - spin_lock_init(&f->fi_ast_lock); - init_waitqueue_head(&f->fi_wait); - f->fi_ls = lsinfo; - f->fi_flags = 0; - get_file_info(f); - set_bit(FI_FLAG_OPEN, &f->fi_flags); - - file->private_data = f; - - return 0; -} - -/* Check the user's version matches ours */ -static int check_version(struct dlm_write_request *req) -{ - if (req->version[0] != DLM_DEVICE_VERSION_MAJOR || - (req->version[0] == DLM_DEVICE_VERSION_MAJOR && - req->version[1] > DLM_DEVICE_VERSION_MINOR)) { - - printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " - "user (%d.%d.%d) kernel (%d.%d.%d)\n", - current->comm, - current->pid, - req->version[0], - req->version[1], - req->version[2], - DLM_DEVICE_VERSION_MAJOR, - DLM_DEVICE_VERSION_MINOR, - DLM_DEVICE_VERSION_PATCH); - return -EINVAL; - } - return 0; -} - -/* Close on lockspace device */ -static int dlm_close(struct inode *inode, struct file *file) -{ - struct file_info *f = file->private_data; - struct lock_info li; - struct lock_info *old_li, *safe; - sigset_t tmpsig; - sigset_t allsigs; - struct user_ls *lsinfo; - DECLARE_WAITQUEUE(wq, current); - - lsinfo = find_lockspace(iminor(inode)); - if (!lsinfo) - return -ENOENT; - - /* Mark this closed so that ASTs will not be delivered any more */ - clear_bit(FI_FLAG_OPEN, &f->fi_flags); - - /* Block signals while we are doing this */ - sigfillset(&allsigs); - sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); - - /* We use our own lock_info struct here, so that any - * outstanding "real" ASTs will be delivered with the - * corresponding "real" params, thus freeing the lock_info - * that belongs the lock. This catches the corner case where - * a lock is BUSY when we try to unlock it here - */ - memset(&li, 0, sizeof(li)); - clear_bit(LI_FLAG_COMPLETE, &li.li_flags); - init_waitqueue_head(&li.li_waitq); - add_wait_queue(&li.li_waitq, &wq); - - /* - * Free any outstanding locks, they are on the - * list in LIFO order so there should be no problems - * about unlocking parents before children. - */ - list_for_each_entry_safe(old_li, safe, &f->fi_li_list, li_ownerqueue) { - int status; - int flags = 0; - - /* Don't unlock persistent locks, just mark them orphaned */ - if (test_bit(LI_FLAG_PERSISTENT, &old_li->li_flags)) { - list_del(&old_li->li_ownerqueue); - - /* Update master copy */ - /* TODO: Check locking core updates the local and - remote ORPHAN flags */ - li.li_lksb.sb_lkid = old_li->li_lksb.sb_lkid; - status = dlm_lock(f->fi_ls->ls_lockspace, - old_li->li_grmode, &li.li_lksb, - DLM_LKF_CONVERT|DLM_LKF_ORPHAN, - NULL, 0, 0, ast_routine, NULL, NULL); - if (status != 0) - printk("dlm: Error orphaning lock %x: %d\n", - old_li->li_lksb.sb_lkid, status); - - /* But tidy our references in it */ - release_lockinfo(old_li->li_file->fi_ls, old_li); - continue; - } - - clear_bit(LI_FLAG_COMPLETE, &li.li_flags); - - flags = DLM_LKF_FORCEUNLOCK; - if (old_li->li_grmode >= DLM_LOCK_PW) - flags |= DLM_LKF_IVVALBLK; - - status = dlm_unlock(f->fi_ls->ls_lockspace, - old_li->li_lksb.sb_lkid, flags, - &li.li_lksb, &li); - - /* Must wait for it to complete as the next lock could be its - * parent */ - if (status == 0) - wait_for_ast(&li); - - /* Unlock suceeded, free the lock_info struct. */ - if (status == 0) - release_lockinfo(old_li->li_file->fi_ls, old_li); - } - - remove_wait_queue(&li.li_waitq, &wq); - - /* - * If this is the last reference to the lockspace - * then free the struct. If it's an AUTOFREE lockspace - * then free the whole thing. - */ - mutex_lock(&user_ls_lock); - if (atomic_dec_and_test(&lsinfo->ls_refcnt)) { - - if (lsinfo->ls_lockspace) { - if (test_bit(LS_FLAG_AUTOFREE, &lsinfo->ls_flags)) { - unregister_lockspace(lsinfo, 1); - } - } else { - kfree(lsinfo->ls_miscinfo.name); - kfree(lsinfo); - } - } - mutex_unlock(&user_ls_lock); - put_file_info(f); - - /* Restore signals */ - sigprocmask(SIG_SETMASK, &tmpsig, NULL); - recalc_sigpending(); - - return 0; -} - -static int do_user_create_lockspace(struct file_info *fi, uint8_t cmd, - struct dlm_lspace_params *kparams) -{ - int status; - struct user_ls *lsinfo; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - status = register_lockspace(kparams->name, &lsinfo, kparams->flags); - - /* If it succeeded then return the minor number */ - if (status == 0) - status = lsinfo->ls_miscinfo.minor; - - return status; -} - -static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, - struct dlm_lspace_params *kparams) -{ - int status; - int force = 1; - struct user_ls *lsinfo; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - mutex_lock(&user_ls_lock); - lsinfo = __find_lockspace(kparams->minor); - if (!lsinfo) { - mutex_unlock(&user_ls_lock); - return -EINVAL; - } - - if (kparams->flags & DLM_USER_LSFLG_FORCEFREE) - force = 3; - - status = unregister_lockspace(lsinfo, force); - mutex_unlock(&user_ls_lock); - - return status; -} - -/* Read call, might block if no ASTs are waiting. - * It will only ever return one message at a time, regardless - * of how many are pending. - */ -static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, - loff_t *ppos) -{ - struct file_info *fi = file->private_data; - struct ast_info *ast; - void *data; - int data_size; - int struct_size; - int offset; - DECLARE_WAITQUEUE(wait, current); -#ifdef CONFIG_COMPAT - struct dlm_lock_result32 result32; - - if (count < sizeof(struct dlm_lock_result32)) -#else - if (count < sizeof(struct dlm_lock_result)) -#endif - return -EINVAL; - - spin_lock(&fi->fi_ast_lock); - if (list_empty(&fi->fi_ast_list)) { - - /* No waiting ASTs. - * Return EOF if the lockspace been deleted. - */ - if (test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags)) - return 0; - - if (file->f_flags & O_NONBLOCK) { - spin_unlock(&fi->fi_ast_lock); - return -EAGAIN; - } - - add_wait_queue(&fi->fi_wait, &wait); - - repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (list_empty(&fi->fi_ast_list) && - !signal_pending(current)) { - - spin_unlock(&fi->fi_ast_lock); - schedule(); - spin_lock(&fi->fi_ast_lock); - goto repeat; - } - - current->state = TASK_RUNNING; - remove_wait_queue(&fi->fi_wait, &wait); - - if (signal_pending(current)) { - spin_unlock(&fi->fi_ast_lock); - return -ERESTARTSYS; - } - } - - ast = list_entry(fi->fi_ast_list.next, struct ast_info, list); - list_del(&ast->list); - spin_unlock(&fi->fi_ast_lock); - - /* Work out the size of the returned data */ -#ifdef CONFIG_COMPAT - if (test_bit(FI_FLAG_COMPAT, &fi->fi_flags)) { - data_size = struct_size = sizeof(struct dlm_lock_result32); - data = &result32; - } - else -#endif - { - data_size = struct_size = sizeof(struct dlm_lock_result); - data = &ast->result; - } - if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) - data_size += DLM_USER_LVB_LEN; - - offset = struct_size; - - /* Room for the extended data ? */ - if (count >= data_size) { - - if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) { - if (copy_to_user(buffer+offset, - ast->result.lksb.sb_lvbptr, - DLM_USER_LVB_LEN)) - return -EFAULT; - ast->result.lvb_offset = offset; - offset += DLM_USER_LVB_LEN; - } - } - - ast->result.length = data_size; - -#ifdef CONFIG_COMPAT - compat_output(&ast->result, &result32); -#endif - - /* Copy the header now it has all the offsets in it */ - if (copy_to_user(buffer, data, struct_size)) - offset = -EFAULT; - - /* If we only returned a header and there's more to come then put it - back on the list */ - if (count < data_size) { - spin_lock(&fi->fi_ast_lock); - list_add(&ast->list, &fi->fi_ast_list); - spin_unlock(&fi->fi_ast_lock); - } else - kfree(ast); - return offset; -} - -static unsigned int dlm_poll(struct file *file, poll_table *wait) -{ - struct file_info *fi = file->private_data; - - poll_wait(file, &fi->fi_wait, wait); - - spin_lock(&fi->fi_ast_lock); - if (!list_empty(&fi->fi_ast_list)) { - spin_unlock(&fi->fi_ast_lock); - return POLLIN | POLLRDNORM; - } - - spin_unlock(&fi->fi_ast_lock); - return 0; -} - -static struct lock_info *allocate_lockinfo(struct file_info *fi, uint8_t cmd, - struct dlm_lock_params *kparams) -{ - struct lock_info *li; - - if (!try_module_get(THIS_MODULE)) - return NULL; - - li = kzalloc(sizeof(struct lock_info), GFP_KERNEL); - if (li) { - li->li_magic = LOCKINFO_MAGIC; - li->li_file = fi; - li->li_cmd = cmd; - li->li_flags = 0; - li->li_grmode = -1; - li->li_rqmode = -1; - li->li_pend_bastparam = NULL; - li->li_pend_bastaddr = NULL; - li->li_castaddr = NULL; - li->li_castparam = NULL; - li->li_lksb.sb_lvbptr = NULL; - li->li_bastaddr = kparams->bastaddr; - li->li_bastparam = kparams->bastparam; - - get_file_info(fi); - } - return li; -} - -static int do_user_lock(struct file_info *fi, uint8_t cmd, - struct dlm_lock_params *kparams) -{ - struct lock_info *li; - int status; - - /* - * Validate things that we need to have correct. - */ - if (!kparams->castaddr) - return -EINVAL; - - if (!kparams->lksb) - return -EINVAL; - - /* Persistent child locks are not available yet */ - if ((kparams->flags & DLM_LKF_PERSISTENT) && kparams->parent) - return -EINVAL; - - /* For conversions, there should already be a lockinfo struct, - unless we are adopting an orphaned persistent lock */ - if (kparams->flags & DLM_LKF_CONVERT) { - - li = get_lockinfo(fi->fi_ls, kparams->lkid); - - /* If this is a persistent lock we will have to create a - lockinfo again */ - if (!li && (kparams->flags & DLM_LKF_PERSISTENT)) { - li = allocate_lockinfo(fi, cmd, kparams); - if (!li) - return -ENOMEM; - - li->li_lksb.sb_lkid = kparams->lkid; - li->li_castaddr = kparams->castaddr; - li->li_castparam = kparams->castparam; - - /* OK, this isn't exactly a FIRSTLOCK but it is the - first time we've used this lockinfo, and if things - fail we want rid of it */ - init_completion(&li->li_firstcomp); - set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); - add_lockinfo(fi->fi_ls, li); - - /* TODO: do a query to get the current state ?? */ - } - if (!li) - return -EINVAL; - - if (li->li_magic != LOCKINFO_MAGIC) - return -EINVAL; - - /* For conversions don't overwrite the current blocking AST - info so that: - a) if a blocking AST fires before the conversion is queued - it runs the current handler - b) if the conversion is cancelled, the original blocking AST - declaration is active - The pend_ info is made active when the conversion - completes. - */ - li->li_pend_bastaddr = kparams->bastaddr; - li->li_pend_bastparam = kparams->bastparam; - } else { - li = allocate_lockinfo(fi, cmd, kparams); - if (!li) - return -ENOMEM; - - /* Allow us to complete our work before - the AST routine runs. In fact we only need (and use) this - when the initial lock fails */ - init_completion(&li->li_firstcomp); - set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); - } - - li->li_user_lksb = kparams->lksb; - li->li_castaddr = kparams->castaddr; - li->li_castparam = kparams->castparam; - li->li_lksb.sb_lkid = kparams->lkid; - li->li_rqmode = kparams->mode; - if (kparams->flags & DLM_LKF_PERSISTENT) - set_bit(LI_FLAG_PERSISTENT, &li->li_flags); - - /* Copy in the value block */ - if (kparams->flags & DLM_LKF_VALBLK) { - if (!li->li_lksb.sb_lvbptr) { - li->li_lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, - GFP_KERNEL); - if (!li->li_lksb.sb_lvbptr) { - status = -ENOMEM; - goto out_err; - } - } - - memcpy(li->li_lksb.sb_lvbptr, kparams->lvb, DLM_USER_LVB_LEN); - } - - /* Lock it ... */ - status = dlm_lock(fi->fi_ls->ls_lockspace, - kparams->mode, &li->li_lksb, - kparams->flags, - kparams->name, kparams->namelen, - kparams->parent, - ast_routine, - li, - (li->li_pend_bastaddr || li->li_bastaddr) ? - bast_routine : NULL); - if (status) - goto out_err; - - /* If it succeeded (this far) with a new lock then keep track of - it on the file's lockinfo list */ - if (!status && test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) { - - spin_lock(&fi->fi_li_lock); - list_add(&li->li_ownerqueue, &fi->fi_li_list); - set_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&fi->fi_li_lock); - if (add_lockinfo(fi->fi_ls, li)) - printk(KERN_WARNING "Add lockinfo failed\n"); - - complete(&li->li_firstcomp); - } - - /* Return the lockid as the user needs it /now/ */ - return li->li_lksb.sb_lkid; - - out_err: - if (test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) - release_lockinfo(fi->fi_ls, li); - return status; - -} - -static int do_user_unlock(struct file_info *fi, uint8_t cmd, - struct dlm_lock_params *kparams) -{ - struct lock_info *li; - int status; - int convert_cancel = 0; - - li = get_lockinfo(fi->fi_ls, kparams->lkid); - if (!li) { - li = allocate_lockinfo(fi, cmd, kparams); - if (!li) - return -ENOMEM; - spin_lock(&fi->fi_li_lock); - list_add(&li->li_ownerqueue, &fi->fi_li_list); - set_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&fi->fi_li_lock); - } - - if (li->li_magic != LOCKINFO_MAGIC) - return -EINVAL; - - li->li_user_lksb = kparams->lksb; - li->li_castparam = kparams->castparam; - li->li_cmd = cmd; - - /* Cancelling a conversion doesn't remove the lock...*/ - if (kparams->flags & DLM_LKF_CANCEL && li->li_grmode != -1) - convert_cancel = 1; - - /* Wait until dlm_lock() has completed */ - if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) { - wait_for_completion(&li->li_firstcomp); - } - - /* dlm_unlock() passes a 0 for castaddr which means don't overwrite - the existing li_castaddr as that's the completion routine for - unlocks. dlm_unlock_wait() specifies a new AST routine to be - executed when the unlock completes. */ - if (kparams->castaddr) - li->li_castaddr = kparams->castaddr; - - /* Use existing lksb & astparams */ - status = dlm_unlock(fi->fi_ls->ls_lockspace, - kparams->lkid, - kparams->flags, &li->li_lksb, li); - - if (!status && !convert_cancel) { - spin_lock(&fi->fi_li_lock); - list_del(&li->li_ownerqueue); - clear_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&fi->fi_li_lock); - } - - return status; -} - -/* Write call, submit a locking request */ -static ssize_t dlm_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct file_info *fi = file->private_data; - struct dlm_write_request *kparams; - sigset_t tmpsig; - sigset_t allsigs; - int status; - -#ifdef CONFIG_COMPAT - if (count < sizeof(struct dlm_write_request32)) -#else - if (count < sizeof(struct dlm_write_request)) -#endif - return -EINVAL; - - if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN) - return -EINVAL; - - /* Has the lockspace been deleted */ - if (fi && test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags)) - return -ENOENT; - - kparams = kmalloc(count, GFP_KERNEL); - if (!kparams) - return -ENOMEM; - - status = -EFAULT; - /* Get the command info */ - if (copy_from_user(kparams, buffer, count)) - goto out_free; - - status = -EBADE; - if (check_version(kparams)) - goto out_free; - -#ifdef CONFIG_COMPAT - if (!kparams->is64bit) { - struct dlm_write_request32 *k32params = (struct dlm_write_request32 *)kparams; - kparams = kmalloc(count + (sizeof(struct dlm_write_request) - sizeof(struct dlm_write_request32)), GFP_KERNEL); - if (!kparams) - return -ENOMEM; - - if (fi) - set_bit(FI_FLAG_COMPAT, &fi->fi_flags); - compat_input(kparams, k32params); - kfree(k32params); - } -#endif - - /* Block signals while we are doing this */ - sigfillset(&allsigs); - sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); - - status = -EINVAL; - switch (kparams->cmd) - { - case DLM_USER_LOCK: - if (!fi) goto out_sig; - status = do_user_lock(fi, kparams->cmd, &kparams->i.lock); - break; - - case DLM_USER_UNLOCK: - if (!fi) goto out_sig; - status = do_user_unlock(fi, kparams->cmd, &kparams->i.lock); - break; - - case DLM_USER_CREATE_LOCKSPACE: - if (fi) goto out_sig; - status = do_user_create_lockspace(fi, kparams->cmd, - &kparams->i.lspace); - break; - - case DLM_USER_REMOVE_LOCKSPACE: - if (fi) goto out_sig; - status = do_user_remove_lockspace(fi, kparams->cmd, - &kparams->i.lspace); - break; - default: - printk("Unknown command passed to DLM device : %d\n", - kparams->cmd); - break; - } - - out_sig: - /* Restore signals */ - sigprocmask(SIG_SETMASK, &tmpsig, NULL); - recalc_sigpending(); - - out_free: - kfree(kparams); - if (status == 0) - return count; - else - return status; -} - -static struct file_operations _dlm_fops = { - .open = dlm_open, - .release = dlm_close, - .read = dlm_read, - .write = dlm_write, - .poll = dlm_poll, - .owner = THIS_MODULE, -}; - -static struct file_operations _dlm_ctl_fops = { - .open = dlm_ctl_open, - .release = dlm_ctl_close, - .write = dlm_write, - .owner = THIS_MODULE, -}; - -/* - * Create control device - */ -static int __init dlm_device_init(void) -{ - int r; - - INIT_LIST_HEAD(&user_ls_list); - mutex_init(&user_ls_lock); - - ctl_device.name = "dlm-control"; - ctl_device.fops = &_dlm_ctl_fops; - ctl_device.minor = MISC_DYNAMIC_MINOR; - - r = misc_register(&ctl_device); - if (r) { - printk(KERN_ERR "dlm: misc_register failed for control dev\n"); - return r; - } - - return 0; -} - -static void __exit dlm_device_exit(void) -{ - misc_deregister(&ctl_device); -} - -MODULE_DESCRIPTION("Distributed Lock Manager device interface"); -MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); - -module_init(dlm_device_init); -module_exit(dlm_device_exit); diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 149106f2b80fab..db080de2a7e91d 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ struct dlm_mhandle; #define log_error(ls, fmt, args...) \ printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args) +#define DLM_LOG_DEBUG #ifdef DLM_LOG_DEBUG #define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args) #else @@ -204,6 +206,9 @@ struct dlm_args { #define DLM_IFL_MSTCPY 0x00010000 #define DLM_IFL_RESEND 0x00020000 +#define DLM_IFL_DEAD 0x00040000 +#define DLM_IFL_USER 0x00000001 +#define DLM_IFL_ORPHAN 0x00000002 struct dlm_lkb { struct dlm_rsb *lkb_resource; /* the rsb */ @@ -231,6 +236,7 @@ struct dlm_lkb { struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */ struct list_head lkb_wait_reply; /* waiting for remote reply */ struct list_head lkb_astqueue; /* need ast to be sent */ + struct list_head lkb_ownqueue; /* list of locks for a process */ char *lkb_lvbptr; struct dlm_lksb *lkb_lksb; /* caller's status block */ @@ -409,6 +415,7 @@ struct rcom_lock { struct dlm_ls { struct list_head ls_list; /* list of lockspaces */ + dlm_lockspace_t *ls_local_handle; uint32_t ls_global_id; /* global unique lockspace ID */ uint32_t ls_exflags; int ls_lvblen; @@ -444,6 +451,8 @@ struct dlm_ls { wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ int ls_uevent_result; + struct miscdevice ls_device; + /* recovery related */ struct timer_list ls_timer; @@ -461,6 +470,7 @@ struct dlm_ls { spinlock_t ls_recover_list_lock; int ls_recover_list_count; wait_queue_head_t ls_wait_general; + struct mutex ls_clear_proc_locks; struct list_head ls_root_list; /* root resources */ struct rw_semaphore ls_root_sem; /* protect root_list */ @@ -475,6 +485,40 @@ struct dlm_ls { #define LSFL_RCOM_READY 3 #define LSFL_UEVENT_WAIT 4 +/* much of this is just saving user space pointers associated with the + lock that we pass back to the user lib with an ast */ + +struct dlm_user_args { + struct dlm_user_proc *proc; /* each process that opens the lockspace + device has private data + (dlm_user_proc) on the struct file, + the process's locks point back to it*/ + struct dlm_lksb lksb; + int old_mode; + int update_user_lvb; + struct dlm_lksb __user *user_lksb; + void __user *castparam; + void __user *castaddr; + void __user *bastparam; + void __user *bastaddr; +}; + +#define DLM_PROC_FLAGS_CLOSING 1 +#define DLM_PROC_FLAGS_COMPAT 2 + +/* locks list is kept so we can remove all a process's locks when it + exits (or orphan those that are persistent) */ + +struct dlm_user_proc { + dlm_lockspace_t *lockspace; + unsigned long flags; /* DLM_PROC_FLAGS */ + struct list_head asts; + spinlock_t asts_spin; + struct list_head locks; + spinlock_t locks_spin; + wait_queue_head_t wait; +}; + static inline int dlm_locking_stopped(struct dlm_ls *ls) { return !test_bit(LSFL_RUNNING, &ls->ls_flags); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 5f69639041078f..4e222f873b6c0d 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -55,8 +55,9 @@ R: do_xxxx() L: receive_xxxx_reply() <- R: send_xxxx_reply() */ - +#include #include "dlm_internal.h" +#include #include "memory.h" #include "lowcomms.h" #include "requestqueue.h" @@ -69,6 +70,7 @@ #include "rcom.h" #include "recover.h" #include "lvb_table.h" +#include "user.h" #include "config.h" static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb); @@ -84,6 +86,8 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, struct dlm_message *ms); static int receive_extralen(struct dlm_message *ms); +#define FAKE_USER_AST (void*)0xff00ff00 + /* * Lock compatibilty matrix - thanks Steve * UN = Unlocked state. Not really a state, used as a flag @@ -152,7 +156,7 @@ static const int __quecvt_compat_matrix[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0} /* PD */ }; -static void dlm_print_lkb(struct dlm_lkb *lkb) +void dlm_print_lkb(struct dlm_lkb *lkb) { printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n" " status %d rqmode %d grmode %d wait_type %d ast_type %d\n", @@ -291,7 +295,7 @@ static int search_rsb_list(struct list_head *head, char *name, int len, if (len == r->res_length && !memcmp(name, r->res_name, len)) goto found; } - return -ENOENT; + return -EBADR; found: if (r->res_nodeid && (flags & R_MASTER)) @@ -376,7 +380,7 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen, if (!error) goto out; - if (error == -ENOENT && !(flags & R_CREATE)) + if (error == -EBADR && !(flags & R_CREATE)) goto out; /* the rsb was found but wasn't a master copy */ @@ -920,7 +924,7 @@ static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb, if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) return; - b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1]; + b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1]; if (b == 1) { int len = receive_extralen(ms); memcpy(lkb->lkb_lvbptr, ms->m_extra, len); @@ -963,6 +967,8 @@ static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) lkb->lkb_rqmode = DLM_LOCK_IV; switch (lkb->lkb_status) { + case DLM_LKSTS_GRANTED: + break; case DLM_LKSTS_CONVERT: move_lkb(r, lkb, DLM_LKSTS_GRANTED); break; @@ -1727,6 +1733,11 @@ static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) return -DLM_EUNLOCK; } +/* FIXME: if revert_lock() finds that the lkb is granted, we should + skip the queue_cast(ECANCEL). It indicates that the request/convert + completed (and queued a normal ast) just before the cancel; we don't + want to clobber the sb_result for the normal ast with ECANCEL. */ + static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb) { revert_lock(r, lkb); @@ -2739,7 +2750,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) confirm_master(r, error); break; - case -ENOENT: + case -EBADR: case -ENOTBLK: /* find_rsb failed to find rsb or rsb wasn't master */ r->res_nodeid = -1; @@ -3545,3 +3556,284 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) return 0; } +int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, + int mode, uint32_t flags, void *name, unsigned int namelen, + uint32_t parent_lkid) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + int error; + + lock_recovery(ls); + + error = create_lkb(ls, &lkb); + if (error) { + kfree(ua); + goto out; + } + + if (flags & DLM_LKF_VALBLK) { + ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + if (!ua->lksb.sb_lvbptr) { + kfree(ua); + __put_lkb(ls, lkb); + error = -ENOMEM; + goto out; + } + } + + /* After ua is attached to lkb it will be freed by free_lkb(). + When DLM_IFL_USER is set, the dlm knows that this is a userspace + lock and that lkb_astparam is the dlm_user_args structure. */ + + error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid, + FAKE_USER_AST, ua, FAKE_USER_AST, &args); + lkb->lkb_flags |= DLM_IFL_USER; + ua->old_mode = DLM_LOCK_IV; + + if (error) { + __put_lkb(ls, lkb); + goto out; + } + + error = request_lock(ls, lkb, name, namelen, &args); + + switch (error) { + case 0: + break; + case -EINPROGRESS: + error = 0; + break; + case -EAGAIN: + error = 0; + /* fall through */ + default: + __put_lkb(ls, lkb); + goto out; + } + + /* add this new lkb to the per-process list of locks */ + spin_lock(&ua->proc->locks_spin); + kref_get(&lkb->lkb_ref); + list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks); + spin_unlock(&ua->proc->locks_spin); + out: + unlock_recovery(ls); + return error; +} + +int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + int mode, uint32_t flags, uint32_t lkid, char *lvb_in) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + /* user can change the params on its lock when it converts it, or + add an lvb that didn't exist before */ + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) { + ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + if (!ua->lksb.sb_lvbptr) { + error = -ENOMEM; + goto out_put; + } + } + if (lvb_in && ua->lksb.sb_lvbptr) + memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); + + ua->castparam = ua_tmp->castparam; + ua->castaddr = ua_tmp->castaddr; + ua->bastparam = ua_tmp->bastparam; + ua->bastaddr = ua_tmp->bastaddr; + ua->old_mode = lkb->lkb_grmode; + + error = set_lock_args(mode, &ua->lksb, flags, 0, 0, FAKE_USER_AST, ua, + FAKE_USER_AST, &args); + if (error) + goto out_put; + + error = convert_lock(ls, lkb, &args); + + if (error == -EINPROGRESS || error == -EAGAIN) + error = 0; + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + kfree(ua_tmp); + return error; +} + +int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid, char *lvb_in) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (lvb_in && ua->lksb.sb_lvbptr) + memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); + ua->castparam = ua_tmp->castparam; + + error = set_unlock_args(flags, ua, &args); + if (error) + goto out_put; + + error = unlock_lock(ls, lkb, &args); + + if (error == -DLM_EUNLOCK) + error = 0; + if (error) + goto out_put; + + spin_lock(&ua->proc->locks_spin); + list_del(&lkb->lkb_ownqueue); + spin_unlock(&ua->proc->locks_spin); + + /* this removes the reference for the proc->locks list added by + dlm_user_request */ + unhold_lkb(lkb); + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + return error; +} + +int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + ua->castparam = ua_tmp->castparam; + + error = set_unlock_args(flags, ua, &args); + if (error) + goto out_put; + + error = cancel_lock(ls, lkb, &args); + + if (error == -DLM_ECANCEL) + error = 0; + if (error) + goto out_put; + + /* this lkb was removed from the WAITING queue */ + if (lkb->lkb_grmode == DLM_LOCK_IV) { + spin_lock(&ua->proc->locks_spin); + list_del(&lkb->lkb_ownqueue); + spin_unlock(&ua->proc->locks_spin); + unhold_lkb(lkb); + } + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + return error; +} + +static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (ua->lksb.sb_lvbptr) + kfree(ua->lksb.sb_lvbptr); + kfree(ua); + lkb->lkb_astparam = (long)NULL; + + /* TODO: propogate to master if needed */ + return 0; +} + +/* The force flag allows the unlock to go ahead even if the lkb isn't granted. + Regardless of what rsb queue the lock is on, it's removed and freed. */ + +static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam; + struct dlm_args args; + int error; + + /* FIXME: we need to handle the case where the lkb is in limbo + while the rsb is being looked up, currently we assert in + _unlock_lock/is_remote because rsb nodeid is -1. */ + + set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args); + + error = unlock_lock(ls, lkb, &args); + if (error == -DLM_EUNLOCK) + error = 0; + return error; +} + +/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which + 1) references lkb->ua which we free here and 2) adds lkbs to proc->asts, + which we clear here. */ + +/* proc CLOSING flag is set so no more device_reads should look at proc->asts + list, and no more device_writes should add lkb's to proc->locks list; so we + shouldn't need to take asts_spin or locks_spin here. this assumes that + device reads/writes/closes are serialized -- FIXME: we may need to serialize + them ourself. */ + +void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) +{ + struct dlm_lkb *lkb, *safe; + + lock_recovery(ls); + mutex_lock(&ls->ls_clear_proc_locks); + + list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) { + if (lkb->lkb_ast_type) { + list_del(&lkb->lkb_astqueue); + unhold_lkb(lkb); + } + + list_del(&lkb->lkb_ownqueue); + + if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) { + lkb->lkb_flags |= DLM_IFL_ORPHAN; + orphan_proc_lock(ls, lkb); + } else { + lkb->lkb_flags |= DLM_IFL_DEAD; + unlock_proc_lock(ls, lkb); + } + + /* this removes the reference for the proc->locks list + added by dlm_user_request, it may result in the lkb + being freed */ + + dlm_put_lkb(lkb); + } + mutex_unlock(&ls->ls_clear_proc_locks); + unlock_recovery(ls); +} diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 56cdc073b1f61b..8d2660f0ab108f 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -14,6 +14,7 @@ #define __LOCK_DOT_H__ void dlm_print_rsb(struct dlm_rsb *r); +void dlm_print_lkb(struct dlm_lkb *lkb); 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, @@ -31,6 +32,16 @@ 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); +int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode, + uint32_t flags, void *name, unsigned int namelen, uint32_t parent_lkid); +int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + int mode, uint32_t flags, uint32_t lkid, char *lvb_in); +int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid, char *lvb_in); +int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid); +void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc); + static inline int is_master(struct dlm_rsb *r) { return !r->res_nodeid; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 9ed4b70348fb68..3f6cb422ac4ba1 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -270,12 +270,36 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id) return ls; } -struct dlm_ls *dlm_find_lockspace_local(void *id) +struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace) { - struct dlm_ls *ls = id; + struct dlm_ls *ls; spin_lock(&lslist_lock); - ls->ls_count++; + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_local_handle == lockspace) { + ls->ls_count++; + goto out; + } + } + ls = NULL; + out: + spin_unlock(&lslist_lock); + return ls; +} + +struct dlm_ls *dlm_find_lockspace_device(int minor) +{ + struct dlm_ls *ls; + + spin_lock(&lslist_lock); + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_device.minor == minor) { + ls->ls_count++; + goto out; + } + } + ls = NULL; + out: spin_unlock(&lslist_lock); return ls; } @@ -436,6 +460,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, init_rwsem(&ls->ls_in_recovery); INIT_LIST_HEAD(&ls->ls_requestqueue); mutex_init(&ls->ls_requestqueue_mutex); + mutex_init(&ls->ls_clear_proc_locks); ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); if (!ls->ls_recover_buf) @@ -444,6 +469,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, INIT_LIST_HEAD(&ls->ls_recover_list); spin_lock_init(&ls->ls_recover_list_lock); ls->ls_recover_list_count = 0; + ls->ls_local_handle = ls; init_waitqueue_head(&ls->ls_wait_general); INIT_LIST_HEAD(&ls->ls_root_list); init_rwsem(&ls->ls_root_sem); diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h index 17bd3ba863a989..891eabbdd021e1 100644 --- a/fs/dlm/lockspace.h +++ b/fs/dlm/lockspace.h @@ -18,6 +18,7 @@ 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); +struct dlm_ls *dlm_find_lockspace_device(int minor); void dlm_put_lockspace(struct dlm_ls *ls); #endif /* __LOCKSPACE_DOT_H__ */ diff --git a/fs/dlm/main.c b/fs/dlm/main.c index 81bf4cb2203344..a8da8dc36b2eee 100644 --- a/fs/dlm/main.c +++ b/fs/dlm/main.c @@ -14,6 +14,7 @@ #include "dlm_internal.h" #include "lockspace.h" #include "lock.h" +#include "user.h" #include "memory.h" #include "lowcomms.h" #include "config.h" @@ -50,10 +51,16 @@ static int __init init_dlm(void) if (error) goto out_debug; + error = dlm_user_init(); + if (error) + goto out_lowcomms; + printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); return 0; + out_lowcomms: + dlm_lowcomms_exit(); out_debug: dlm_unregister_debugfs(); out_config: @@ -68,6 +75,7 @@ static int __init init_dlm(void) static void __exit exit_dlm(void) { + dlm_user_exit(); dlm_lowcomms_exit(); dlm_config_exit(); dlm_memory_exit(); diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index f7cf4589fae8fc..48dfc27861f426 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -84,6 +84,15 @@ struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) void free_lkb(struct dlm_lkb *lkb) { + if (lkb->lkb_flags & DLM_IFL_USER) { + struct dlm_user_args *ua; + ua = (struct dlm_user_args *)lkb->lkb_astparam; + if (ua) { + if (ua->lksb.sb_lvbptr) + kfree(ua->lksb.sb_lvbptr); + kfree(ua); + } + } kmem_cache_free(lkb_cache, lkb); } diff --git a/fs/dlm/user.c b/fs/dlm/user.c new file mode 100644 index 00000000000000..1f05960a916f38 --- /dev/null +++ b/fs/dlm/user.c @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2006 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dlm_internal.h" +#include "lockspace.h" +#include "lock.h" +#include "lvb_table.h" + +static const char *name_prefix="dlm"; +static struct miscdevice ctl_device; +static struct file_operations device_fops; + +#ifdef CONFIG_COMPAT + +struct dlm_lock_params32 { + __u8 mode; + __u8 namelen; + __u16 flags; + __u32 lkid; + __u32 parent; + + __u32 castparam; + __u32 castaddr; + __u32 bastparam; + __u32 bastaddr; + __u32 lksb; + + char lvb[DLM_USER_LVB_LEN]; + char name[0]; +}; + +struct dlm_write_request32 { + __u32 version[3]; + __u8 cmd; + __u8 is64bit; + __u8 unused[2]; + + union { + struct dlm_lock_params32 lock; + struct dlm_lspace_params lspace; + } i; +}; + +struct dlm_lksb32 { + __u32 sb_status; + __u32 sb_lkid; + __u8 sb_flags; + __u32 sb_lvbptr; +}; + +struct dlm_lock_result32 { + __u32 length; + __u32 user_astaddr; + __u32 user_astparam; + __u32 user_lksb; + struct dlm_lksb32 lksb; + __u8 bast_mode; + __u8 unused[3]; + /* Offsets may be zero if no data is present */ + __u32 lvb_offset; +}; + +static void compat_input(struct dlm_write_request *kb, + struct dlm_write_request32 *kb32) +{ + kb->version[0] = kb32->version[0]; + kb->version[1] = kb32->version[1]; + kb->version[2] = kb32->version[2]; + + kb->cmd = kb32->cmd; + kb->is64bit = kb32->is64bit; + if (kb->cmd == DLM_USER_CREATE_LOCKSPACE || + kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { + kb->i.lspace.flags = kb32->i.lspace.flags; + kb->i.lspace.minor = kb32->i.lspace.minor; + strcpy(kb->i.lspace.name, kb32->i.lspace.name); + } else { + kb->i.lock.mode = kb32->i.lock.mode; + kb->i.lock.namelen = kb32->i.lock.namelen; + kb->i.lock.flags = kb32->i.lock.flags; + kb->i.lock.lkid = kb32->i.lock.lkid; + kb->i.lock.parent = kb32->i.lock.parent; + kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam; + kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr; + kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam; + kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; + kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; + memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); + memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen); + } +} + +static void compat_output(struct dlm_lock_result *res, + struct dlm_lock_result32 *res32) +{ + res32->length = res->length - (sizeof(struct dlm_lock_result) - + sizeof(struct dlm_lock_result32)); + res32->user_astaddr = (__u32)(long)res->user_astaddr; + res32->user_astparam = (__u32)(long)res->user_astparam; + res32->user_lksb = (__u32)(long)res->user_lksb; + res32->bast_mode = res->bast_mode; + + res32->lvb_offset = res->lvb_offset; + res32->length = res->length; + + res32->lksb.sb_status = res->lksb.sb_status; + res32->lksb.sb_flags = res->lksb.sb_flags; + res32->lksb.sb_lkid = res->lksb.sb_lkid; + res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; +} +#endif + + +void dlm_user_add_ast(struct dlm_lkb *lkb, int type) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + struct dlm_user_proc *proc; + + /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each + lkb before dealing with it. We need to check this + flag before taking ls_clear_proc_locks mutex because if + it's set, dlm_clear_proc_locks() holds the mutex. */ + + if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) { + /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */ + return; + } + + ls = lkb->lkb_resource->res_ls; + mutex_lock(&ls->ls_clear_proc_locks); + + /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast + can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed + lkb->ua so we can't try to use it. */ + + if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) { + /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */ + goto out; + } + + DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb);); + ua = (struct dlm_user_args *)lkb->lkb_astparam; + proc = ua->proc; + + if (type == AST_BAST && ua->bastaddr == NULL) + goto out; + + spin_lock(&proc->asts_spin); + if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { + kref_get(&lkb->lkb_ref); + list_add_tail(&lkb->lkb_astqueue, &proc->asts); + lkb->lkb_ast_type |= type; + wake_up_interruptible(&proc->wait); + } + + /* We want to copy the lvb to userspace when the completion + ast is read if the status is 0, the lock has an lvb and + lvb_ops says we should. We could probably have set_lvb_lock() + set update_user_lvb instead and not need old_mode */ + + if ((lkb->lkb_ast_type & AST_COMP) && + (lkb->lkb_lksb->sb_status == 0) && + lkb->lkb_lksb->sb_lvbptr && + dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1]) + ua->update_user_lvb = 1; + else + ua->update_user_lvb = 0; + + spin_unlock(&proc->asts_spin); + out: + mutex_unlock(&ls->ls_clear_proc_locks); +} + +static int device_user_lock(struct dlm_user_proc *proc, + struct dlm_lock_params *params) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + int error = -ENOMEM; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + if (!params->castaddr || !params->lksb) { + error = -EINVAL; + goto out; + } + + ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); + if (!ua) + goto out; + ua->proc = proc; + ua->user_lksb = params->lksb; + ua->castparam = params->castparam; + ua->castaddr = params->castaddr; + ua->bastparam = params->bastparam; + ua->bastaddr = params->bastaddr; + + if (params->flags & DLM_LKF_CONVERT) + error = dlm_user_convert(ls, ua, + params->mode, params->flags, + params->lkid, params->lvb); + else { + error = dlm_user_request(ls, ua, + params->mode, params->flags, + params->name, params->namelen, + params->parent); + if (!error) + error = ua->lksb.sb_lkid; + } + out: + dlm_put_lockspace(ls); + return error; +} + +static int device_user_unlock(struct dlm_user_proc *proc, + struct dlm_lock_params *params) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + int error = -ENOMEM; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); + if (!ua) + goto out; + ua->proc = proc; + ua->user_lksb = params->lksb; + ua->castparam = params->castparam; + ua->castaddr = params->castaddr; + + if (params->flags & DLM_LKF_CANCEL) + error = dlm_user_cancel(ls, ua, params->flags, params->lkid); + else + error = dlm_user_unlock(ls, ua, params->flags, params->lkid, + params->lvb); + out: + dlm_put_lockspace(ls); + return error; +} + +static int device_create_lockspace(struct dlm_lspace_params *params) +{ + dlm_lockspace_t *lockspace; + struct dlm_ls *ls; + int error, len; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + error = dlm_new_lockspace(params->name, strlen(params->name), + &lockspace, 0, DLM_USER_LVB_LEN); + if (error) + return error; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -ENOENT; + + error = -ENOMEM; + len = strlen(params->name) + strlen(name_prefix) + 2; + ls->ls_device.name = kzalloc(len, GFP_KERNEL); + if (!ls->ls_device.name) + goto fail; + snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix, + params->name); + ls->ls_device.fops = &device_fops; + ls->ls_device.minor = MISC_DYNAMIC_MINOR; + + error = misc_register(&ls->ls_device); + if (error) { + kfree(ls->ls_device.name); + goto fail; + } + + error = ls->ls_device.minor; + dlm_put_lockspace(ls); + return error; + + fail: + dlm_put_lockspace(ls); + dlm_release_lockspace(lockspace, 0); + return error; +} + +static int device_remove_lockspace(struct dlm_lspace_params *params) +{ + dlm_lockspace_t *lockspace; + struct dlm_ls *ls; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ls = dlm_find_lockspace_device(params->minor); + if (!ls) + return -ENOENT; + + error = misc_deregister(&ls->ls_device); + if (error) { + dlm_put_lockspace(ls); + goto out; + } + kfree(ls->ls_device.name); + + lockspace = ls->ls_local_handle; + + /* dlm_release_lockspace waits for references to go to zero, + so all processes will need to close their device for the ls + before the release will procede */ + + dlm_put_lockspace(ls); + error = dlm_release_lockspace(lockspace, 0); +out: + return error; +} + +/* Check the user's version matches ours */ +static int check_version(struct dlm_write_request *req) +{ + if (req->version[0] != DLM_DEVICE_VERSION_MAJOR || + (req->version[0] == DLM_DEVICE_VERSION_MAJOR && + req->version[1] > DLM_DEVICE_VERSION_MINOR)) { + + printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " + "user (%d.%d.%d) kernel (%d.%d.%d)\n", + current->comm, + current->pid, + req->version[0], + req->version[1], + req->version[2], + DLM_DEVICE_VERSION_MAJOR, + DLM_DEVICE_VERSION_MINOR, + DLM_DEVICE_VERSION_PATCH); + return -EINVAL; + } + return 0; +} + +/* + * device_write + * + * device_user_lock + * dlm_user_request -> request_lock + * dlm_user_convert -> convert_lock + * + * device_user_unlock + * dlm_user_unlock -> unlock_lock + * dlm_user_cancel -> cancel_lock + * + * device_create_lockspace + * dlm_new_lockspace + * + * device_remove_lockspace + * dlm_release_lockspace + */ + +/* a write to a lockspace device is a lock or unlock request, a write + to the control device is to create/remove a lockspace */ + +static ssize_t device_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_write_request *kbuf; + sigset_t tmpsig, allsigs; + int error; + +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_write_request32)) +#else + if (count < sizeof(struct dlm_write_request)) +#endif + return -EINVAL; + + kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (copy_from_user(kbuf, buf, count)) { + error = -EFAULT; + goto out_free; + } + + if (check_version(kbuf)) { + error = -EBADE; + goto out_free; + } + +#ifdef CONFIG_COMPAT + if (!kbuf->is64bit) { + struct dlm_write_request32 *k32buf; + k32buf = (struct dlm_write_request32 *)kbuf; + kbuf = kmalloc(count + (sizeof(struct dlm_write_request) - + sizeof(struct dlm_write_request32)), GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (proc) + set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); + compat_input(kbuf, k32buf); + kfree(k32buf); + } +#endif + + /* do we really need this? can a write happen after a close? */ + if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) && + test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) + return -EINVAL; + + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + error = -EINVAL; + + switch (kbuf->cmd) + { + case DLM_USER_LOCK: + if (!proc) { + log_print("no locking on control device"); + goto out_sig; + } + error = device_user_lock(proc, &kbuf->i.lock); + break; + + case DLM_USER_UNLOCK: + if (!proc) { + log_print("no locking on control device"); + goto out_sig; + } + error = device_user_unlock(proc, &kbuf->i.lock); + break; + + case DLM_USER_CREATE_LOCKSPACE: + if (proc) { + log_print("create/remove only on control device"); + goto out_sig; + } + error = device_create_lockspace(&kbuf->i.lspace); + break; + + case DLM_USER_REMOVE_LOCKSPACE: + if (proc) { + log_print("create/remove only on control device"); + goto out_sig; + } + error = device_remove_lockspace(&kbuf->i.lspace); + break; + + default: + log_print("Unknown command passed to DLM device : %d\n", + kbuf->cmd); + } + + out_sig: + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + out_free: + kfree(kbuf); + return error; +} + +/* Every process that opens the lockspace device has its own "proc" structure + hanging off the open file that's used to keep track of locks owned by the + process and asts that need to be delivered to the process. */ + +static int device_open(struct inode *inode, struct file *file) +{ + struct dlm_user_proc *proc; + struct dlm_ls *ls; + + ls = dlm_find_lockspace_device(iminor(inode)); + if (!ls) + return -ENOENT; + + proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); + if (!proc) { + dlm_put_lockspace(ls); + return -ENOMEM; + } + + proc->lockspace = ls->ls_local_handle; + INIT_LIST_HEAD(&proc->asts); + INIT_LIST_HEAD(&proc->locks); + spin_lock_init(&proc->asts_spin); + spin_lock_init(&proc->locks_spin); + init_waitqueue_head(&proc->wait); + file->private_data = proc; + + return 0; +} + +static int device_close(struct inode *inode, struct file *file) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_ls *ls; + sigset_t tmpsig, allsigs; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags); + + dlm_clear_proc_locks(ls, proc); + + /* at this point no more lkb's should exist for this lockspace, + so there's no chance of dlm_user_add_ast() being called and + looking for lkb->ua->proc */ + + kfree(proc); + file->private_data = NULL; + + dlm_put_lockspace(ls); + dlm_put_lockspace(ls); /* for the find in device_open() */ + + /* FIXME: AUTOFREE: if this ls is no longer used do + device_remove_lockspace() */ + + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + + return 0; +} + +static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, + int bmode, char __user *buf, size_t count) +{ +#ifdef CONFIG_COMPAT + struct dlm_lock_result32 result32; +#endif + struct dlm_lock_result result; + void *resultptr; + int error=0; + int len; + int struct_len; + + memset(&result, 0, sizeof(struct dlm_lock_result)); + memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb)); + result.user_lksb = ua->user_lksb; + + /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated + in a conversion unless the conversion is successful. See code + in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though, + notes that a new blocking AST address and parameter are set even if + the conversion fails, so maybe we should just do that. */ + + if (type == AST_BAST) { + result.user_astaddr = ua->bastaddr; + result.user_astparam = ua->bastparam; + result.bast_mode = bmode; + } else { + result.user_astaddr = ua->castaddr; + result.user_astparam = ua->castparam; + } + +#ifdef CONFIG_COMPAT + if (compat) + len = sizeof(struct dlm_lock_result32); + else +#endif + len = sizeof(struct dlm_lock_result); + struct_len = len; + + /* copy lvb to userspace if there is one, it's been updated, and + the user buffer has space for it */ + + if (ua->update_user_lvb && ua->lksb.sb_lvbptr && + count >= len + DLM_USER_LVB_LEN) { + if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, + DLM_USER_LVB_LEN)) { + error = -EFAULT; + goto out; + } + + result.lvb_offset = len; + len += DLM_USER_LVB_LEN; + } + + result.length = len; + resultptr = &result; +#ifdef CONFIG_COMPAT + if (compat) { + compat_output(&result, &result32); + resultptr = &result32; + } +#endif + + if (copy_to_user(buf, resultptr, struct_len)) + error = -EFAULT; + else + error = len; + out: + return error; +} + +/* a read returns a single ast described in a struct dlm_lock_result */ + +static ssize_t device_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_lkb *lkb; + struct dlm_user_args *ua; + DECLARE_WAITQUEUE(wait, current); + int error, type=0, bmode=0, removed = 0; + +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_lock_result32)) +#else + if (count < sizeof(struct dlm_lock_result)) +#endif + return -EINVAL; + + /* do we really need this? can a read happen after a close? */ + if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) + return -EINVAL; + + spin_lock(&proc->asts_spin); + if (list_empty(&proc->asts)) { + if (file->f_flags & O_NONBLOCK) { + spin_unlock(&proc->asts_spin); + return -EAGAIN; + } + + add_wait_queue(&proc->wait, &wait); + + repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&proc->asts) && !signal_pending(current)) { + spin_unlock(&proc->asts_spin); + schedule(); + spin_lock(&proc->asts_spin); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&proc->wait, &wait); + + if (signal_pending(current)) { + spin_unlock(&proc->asts_spin); + return -ERESTARTSYS; + } + } + + if (list_empty(&proc->asts)) { + spin_unlock(&proc->asts_spin); + return -EAGAIN; + } + + /* there may be both completion and blocking asts to return for + the lkb, don't remove lkb from asts list unless no asts remain */ + + lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); + + if (lkb->lkb_ast_type & AST_COMP) { + lkb->lkb_ast_type &= ~AST_COMP; + type = AST_COMP; + } else if (lkb->lkb_ast_type & AST_BAST) { + lkb->lkb_ast_type &= ~AST_BAST; + type = AST_BAST; + bmode = lkb->lkb_bastmode; + } + + if (!lkb->lkb_ast_type) { + list_del(&lkb->lkb_astqueue); + removed = 1; + } + spin_unlock(&proc->asts_spin); + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + error = copy_result_to_user(ua, + test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), + type, bmode, buf, count); + + /* removes reference for the proc->asts lists added by + dlm_user_add_ast() and may result in the lkb being freed */ + if (removed) + dlm_put_lkb(lkb); + + return error; +} + +static unsigned int device_poll(struct file *file, poll_table *wait) +{ + struct dlm_user_proc *proc = file->private_data; + + poll_wait(file, &proc->wait, wait); + + spin_lock(&proc->asts_spin); + if (!list_empty(&proc->asts)) { + spin_unlock(&proc->asts_spin); + return POLLIN | POLLRDNORM; + } + spin_unlock(&proc->asts_spin); + return 0; +} + +static int ctl_device_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int ctl_device_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations device_fops = { + .open = device_open, + .release = device_close, + .read = device_read, + .write = device_write, + .poll = device_poll, + .owner = THIS_MODULE, +}; + +static struct file_operations ctl_device_fops = { + .open = ctl_device_open, + .release = ctl_device_close, + .write = device_write, + .owner = THIS_MODULE, +}; + +int dlm_user_init(void) +{ + int error; + + ctl_device.name = "dlm-control"; + ctl_device.fops = &ctl_device_fops; + ctl_device.minor = MISC_DYNAMIC_MINOR; + + error = misc_register(&ctl_device); + if (error) + log_print("misc_register failed for control device"); + + return error; +} + +void dlm_user_exit(void) +{ + misc_deregister(&ctl_device); +} + diff --git a/fs/dlm/user.h b/fs/dlm/user.h new file mode 100644 index 00000000000000..d38e9f3e415118 --- /dev/null +++ b/fs/dlm/user.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2006 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 __USER_DOT_H__ +#define __USER_DOT_H__ + +void dlm_user_add_ast(struct dlm_lkb *lkb, int type); +int dlm_user_init(void); +void dlm_user_exit(void); + +#endif -- cgit 1.2.3-korg From 5de6319b1839300ba6b461ed19531cdab90db9fc Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Jul 2006 13:44:31 -0500 Subject: [DLM] more info through debugfs Display more information from debugfs, particularly locks waiting for a master lookup or operations waiting for a remote reply. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 132 +++++++++++++++++++++++++++++++++++++++++--------- fs/dlm/dlm_internal.h | 3 +- fs/dlm/lockspace.c | 3 +- 3 files changed, 114 insertions(+), 24 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 49deca845dbaf6..5faa747c7ca1fc 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -18,6 +18,9 @@ #include "dlm_internal.h" +#define DLM_DEBUG_BUF_LEN 4096 +static char debug_buf[DLM_DEBUG_BUF_LEN]; +static struct mutex debug_buf_lock; static struct dentry *dlm_root; @@ -28,6 +31,10 @@ struct rsb_iter { struct dlm_rsb *rsb; }; +/* + * dump all rsb's in the lockspace hash table + */ + static char *print_lockmode(int mode) { switch (mode) { @@ -76,7 +83,7 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, static int print_resource(struct dlm_rsb *res, struct seq_file *s) { struct dlm_lkb *lkb; - int i, lvblen = res->res_ls->ls_lvblen; + int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); for (i = 0; i < res->res_length; i++) { @@ -110,6 +117,15 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) seq_printf(s, "\n"); } + root_list = !list_empty(&res->res_root_list); + recover_list = !list_empty(&res->res_recover_list); + + if (root_list || recover_list) { + seq_printf(s, "Recovery: root %d recover %d flags %lx " + "count %d\n", root_list, recover_list, + res->flags, res->res_recover_locks_count); + } + /* Print the locks attached to this resource */ seq_printf(s, "Granted Queue\n"); list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) @@ -123,6 +139,18 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) print_lock(s, lkb, res); + if (list_empty(&res->res_lookup)) + goto out; + + seq_printf(s, "Lookup Queue\n"); + list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { + seq_printf(s, "%08x %s", lkb->lkb_id, + print_lockmode(lkb->lkb_rqmode)); + if (lkb->lkb_wait_type) + seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); + seq_printf(s, "\n"); + } + out: return 0; } @@ -190,7 +218,7 @@ static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) return ri; } -static void *seq_start(struct seq_file *file, loff_t *pos) +static void *rsb_seq_start(struct seq_file *file, loff_t *pos) { struct rsb_iter *ri; loff_t n = *pos; @@ -209,7 +237,7 @@ static void *seq_start(struct seq_file *file, loff_t *pos) return ri; } -static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) +static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) { struct rsb_iter *ri = iter_ptr; @@ -223,12 +251,12 @@ static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) return ri; } -static void seq_stop(struct seq_file *file, void *iter_ptr) +static void rsb_seq_stop(struct seq_file *file, void *iter_ptr) { /* nothing for now */ } -static int seq_show(struct seq_file *file, void *iter_ptr) +static int rsb_seq_show(struct seq_file *file, void *iter_ptr) { struct rsb_iter *ri = iter_ptr; @@ -237,19 +265,19 @@ static int seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations dlm_seq_ops = { - .start = seq_start, - .next = seq_next, - .stop = seq_stop, - .show = seq_show, +static struct seq_operations rsb_seq_ops = { + .start = rsb_seq_start, + .next = rsb_seq_next, + .stop = rsb_seq_stop, + .show = rsb_seq_show, }; -static int do_open(struct inode *inode, struct file *file) +static int rsb_open(struct inode *inode, struct file *file) { struct seq_file *seq; int ret; - ret = seq_open(file, &dlm_seq_ops); + ret = rsb_seq_open(file, &rsb_seq_ops); if (ret) return ret; @@ -259,32 +287,92 @@ static int do_open(struct inode *inode, struct file *file) return 0; } -static struct file_operations dlm_fops = { +static struct file_operations rsb_fops = { .owner = THIS_MODULE, - .open = do_open, + .open = rsb_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; +/* + * dump lkb's on the ls_waiters list + */ + +static int waiters_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t waiters_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct dlm_ls *ls = file->private_data; + struct dlm_lkb *lkb; + size_t len = DLM_DEBUG_BUF_LEN, pos = 0, rv; + + mutex_lock(&debug_buf_lock); + mutex_lock(&ls->ls_waiters_mutex); + memset(debug_buf, 0, sizeof(debug_buf)); + + list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { + pos += snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n", + lkb->lkb_id, lkb->lkb_wait_type, + lkb->lkb_nodeid, lkb->lkb_resource->res_name); + } + mutex_unlock(&ls->ls_waiters_mutex); + + rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos); + mutex_unlock(&debug_buf_lock); + return rv; +} + +static struct file_operations waiters_fops = { + .owner = THIS_MODULE, + .open = waiters_open, + .read = waiters_read +}; + 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; + char name[DLM_LOCKSPACE_LEN+8]; + + ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &rsb_fops); + if (!ls->ls_rsb_debug_dentry) + return -ENOMEM; + + memset(name, 0, sizeof(name)); + snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); + + ls->ls_debug_waiters_dentry = debugfs_create_file(name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &waiters_fops); + if (!ls->ls_debug_waiters_dentry) { + debugfs_remove(ls->ls_debug_rsb_dentry); + return -ENOMEM; + } + + return 0; } void dlm_delete_debug_file(struct dlm_ls *ls) { - if (ls->ls_debug_dentry) - debugfs_remove(ls->ls_debug_dentry); + if (ls->ls_debug_rsb_dentry) + debugfs_remove(ls->ls_debug_rsb_dentry); + if (ls->ls_debug_waiters_dentry) + debugfs_remove(ls->ls_debug_waiters_dentry); } int dlm_register_debugfs(void) { + mutex_init(&debug_buf_lock); dlm_root = debugfs_create_dir("dlm", NULL); return dlm_root ? 0 : -ENOMEM; } diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index db080de2a7e91d..7c3c2d27c012c3 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -446,7 +446,8 @@ struct dlm_ls { struct dlm_lkb ls_stub_lkb; /* for returning errors */ struct dlm_message ls_stub_ms; /* for faking a reply */ - struct dentry *ls_debug_dentry; /* debugfs */ + struct dentry *ls_debug_rsb_dentry; /* debugfs */ + struct dentry *ls_debug_waiters_dentry; /* debugfs */ wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ int ls_uevent_result; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 3f6cb422ac4ba1..31ed0fe16a3161 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -446,7 +446,8 @@ static int new_lockspace(char *name, int namelen, void **lockspace, memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb)); ls->ls_stub_rsb.res_ls = ls; - ls->ls_debug_dentry = NULL; + ls->ls_debug_rsb_dentry = NULL; + ls->ls_debug_waiters_dentry = NULL; init_waitqueue_head(&ls->ls_uevent_wait); ls->ls_uevent_result = 0; -- cgit 1.2.3-korg From faa0f2677287a2e7ae796db8b73618ec43715e94 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 8 Aug 2006 17:08:42 -0500 Subject: [DLM] show nodeid for recovery message To aid debugging, it's useful to be able to see what nodeid the dlm is waiting on for a message reply. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/lockspace.c | 11 +++++++++++ fs/dlm/member.c | 3 ++- fs/dlm/rcom.c | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 7c3c2d27c012c3..ec7e401133fd6c 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -467,6 +467,7 @@ struct dlm_ls { struct list_head ls_requestqueue;/* queue remote requests */ struct mutex ls_requestqueue_mutex; char *ls_recover_buf; + int ls_recover_nodeid; /* for debugging */ struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; int ls_recover_list_count; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 31ed0fe16a3161..7adaad53fc3830 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -81,6 +81,11 @@ static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) return sprintf(buf, "%x\n", status); } +static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->ls_recover_nodeid); +} + struct dlm_attr { struct attribute attr; ssize_t (*show)(struct dlm_ls *, char *); @@ -108,11 +113,17 @@ static struct dlm_attr dlm_attr_recover_status = { .show = dlm_recover_status_show }; +static struct dlm_attr dlm_attr_recover_nodeid = { + .attr = {.name = "recover_nodeid", .mode = S_IRUGO}, + .show = dlm_recover_nodeid_show +}; + static struct attribute *dlm_attrs[] = { &dlm_attr_control.attr, &dlm_attr_event.attr, &dlm_attr_id.attr, &dlm_attr_recover_status.attr, + &dlm_attr_recover_nodeid.attr, NULL, }; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index ebb33c30f0f352..a3f7de7f3a8f96 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -176,7 +176,8 @@ static int ping_members(struct dlm_ls *ls) break; } if (error) - log_debug(ls, "ping_members aborted %d", error); + log_debug(ls, "ping_members aborted %d last nodeid %d", + error, ls->ls_recover_nodeid); return error; } diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 55fbe313340e59..5573d8590e588d 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -97,6 +97,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) int error = 0; memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + ls->ls_recover_nodeid = nodeid; if (nodeid == dlm_our_nodeid()) { rc = (struct dlm_rcom *) ls->ls_recover_buf; @@ -159,6 +160,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) int error = 0, len = sizeof(struct dlm_rcom); memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + ls->ls_recover_nodeid = nodeid; if (nodeid == dlm_our_nodeid()) { dlm_copy_master_names(ls, last_name, last_len, -- cgit 1.2.3-korg From 4a99c3d9d6663085e28bc7ac8dae1e985c5a6174 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 9 Aug 2006 11:20:15 -0500 Subject: [DLM] reject replies to old requests When recoveries are aborted by other recoveries we can get replies to status or names requests that we've given up on. This can cause problems if we're making another request and receive an old reply. Add a sequence number to status/names requests and reject replies that don't match. A field already exists for the seq number that's used in other message types. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/rcom.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index ec7e401133fd6c..da7509986699ff 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -468,6 +468,7 @@ struct dlm_ls { struct mutex ls_requestqueue_mutex; char *ls_recover_buf; int ls_recover_nodeid; /* for debugging */ + uint64_t ls_rcom_seq; struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; int ls_recover_list_count; diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 5573d8590e588d..64ba4929f90b25 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -108,6 +108,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh); if (error) goto out; + rc->rc_id = ++ls->ls_rcom_seq; send_rcom(ls, mh, rc); @@ -140,19 +141,30 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in) sizeof(struct rcom_config), &rc, &mh); if (error) return; + rc->rc_id = rc_in->rc_id; rc->rc_result = dlm_recover_status(ls); make_config(ls, (struct rcom_config *) rc->rc_buf); send_rcom(ls, mh, rc); } -static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) { + if (rc_in->rc_id != ls->ls_rcom_seq) { + log_debug(ls, "reject old reply %d got %llx wanted %llx", + rc_in->rc_type, rc_in->rc_id, ls->ls_rcom_seq); + return; + } memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length); set_bit(LSFL_RCOM_READY, &ls->ls_flags); wake_up(&ls->ls_wait_general); } +static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + receive_sync_reply(ls, rc_in); +} + int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) { struct dlm_rcom *rc; @@ -173,6 +185,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) if (error) goto out; memcpy(rc->rc_buf, last_name, last_len); + rc->rc_id = ++ls->ls_rcom_seq; send_rcom(ls, mh, rc); @@ -209,6 +222,7 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh); if (error) return; + rc->rc_id = rc_in->rc_id; dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen, nodeid); @@ -217,9 +231,7 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) { - memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length); - set_bit(LSFL_RCOM_READY, &ls->ls_flags); - wake_up(&ls->ls_wait_general); + receive_sync_reply(ls, rc_in); } int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) -- cgit 1.2.3-korg From 32f105a123804c7882d447f013aeb3530b4d63c0 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 23 Aug 2006 16:07:31 -0400 Subject: [DLM] down conversion clearing flags The down-conversion optimization was resulting in the lkb flags being cleared because the stub message reply had no flags value set. Copy the current flags into the stub message so they'll be copied back into the lkb as part of processing the fake reply. Also add an assertion to catch this error more directly if it exists elsewhere. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/ast.c | 1 + fs/dlm/dlm_internal.h | 2 ++ fs/dlm/lock.c | 9 ++++----- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'fs/dlm/dlm_internal.h') diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index a211330cbc422e..f91d39cb1e0bd0 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -38,6 +38,7 @@ void dlm_add_ast(struct dlm_lkb *lkb, int type) dlm_user_add_ast(lkb, type); return; } + DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb);); spin_lock(&ast_queue_lock); if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index da7509986699ff..1e5cd67e1b7ad2 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -91,6 +91,8 @@ struct dlm_mhandle; } \ } +#define DLM_FAKE_USER_AST ERR_PTR(-EINVAL) + struct dlm_direntry { struct list_head list; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 6dcd475826c185..67247f0b508a5f 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -86,8 +86,6 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, struct dlm_message *ms); static int receive_extralen(struct dlm_message *ms); -#define FAKE_USER_AST (void*)0xff00ff00 - /* * Lock compatibilty matrix - thanks Steve * UN = Unlocked state. Not really a state, used as a flag @@ -2195,6 +2193,7 @@ static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) if (!error && down_conversion(lkb)) { remove_from_waiters(lkb); r->res_ls->ls_stub_ms.m_result = 0; + r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags; __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms); } @@ -3615,7 +3614,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, lock and that lkb_astparam is the dlm_user_args structure. */ error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid, - FAKE_USER_AST, ua, FAKE_USER_AST, &args); + DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args); lkb->lkb_flags |= DLM_IFL_USER; ua->old_mode = DLM_LOCK_IV; @@ -3686,8 +3685,8 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, ua->user_lksb = ua_tmp->user_lksb; ua->old_mode = lkb->lkb_grmode; - error = set_lock_args(mode, &ua->lksb, flags, 0, 0, FAKE_USER_AST, ua, - FAKE_USER_AST, &args); + error = set_lock_args(mode, &ua->lksb, flags, 0, 0, DLM_FAKE_USER_AST, + ua, DLM_FAKE_USER_AST, &args); if (error) goto out_put; -- cgit 1.2.3-korg