<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kernel sources &#187; debugfs</title>
	<atom:link href="http://lynyrd.ru/category/debugfs/feed" rel="self" type="application/rss+xml" />
	<link>http://lynyrd.ru</link>
	<description></description>
	<lastBuildDate>Sun, 31 Jan 2010 05:51:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>midcomms.c</title>
		<link>http://lynyrd.ru/midcomms-c</link>
		<comments>http://lynyrd.ru/midcomms-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:54:22 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/midcomms-c</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2008 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1053"></span><br />
**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>/*<br />
 * midcomms.c<br />
 *<br />
 * This is the appallingly named &laquo;mid-level&raquo; comms layer.<br />
 *<br />
 * Its purpose is to take packets from the &laquo;real&raquo; comms layer,<br />
 * split them up into packets and pass them to the interested<br />
 * part of the locking mechanism.<br />
 *<br />
 * It also takes messages from the locking layer, formats them<br />
 * into packets and sends them to the comms layer.<br />
 */</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;midcomms.h&raquo;</p>
<p>static void copy_from_cb(void *dst, const void *base, unsigned offset,<br />
			 unsigned len, unsigned limit)<br />
{<br />
	unsigned copy = len;</p>
<p>	if ((copy + offset) > limit)<br />
		copy = limit &#8211; offset;<br />
	memcpy(dst, base + offset, copy);<br />
	len -= copy;<br />
	if (len)<br />
		memcpy(dst + copy, base, len);<br />
}</p>
<p>/*<br />
 * Called from the low-level comms layer to process a buffer of<br />
 * commands.<br />
 *<br />
 * Only complete messages are processed here, any &laquo;spare&raquo; bytes from<br />
 * the end of a buffer are saved and tacked onto the front of the next<br />
 * message that comes in. I doubt this will happen very often but we<br />
 * need to be able to cope with it and I don&#8217;t want the task to be waiting<br />
 * for packets to come in when there is useful work to be done.<br />
 */</p>
<p>int dlm_process_incoming_buffer(int nodeid, const void *base,<br />
				unsigned offset, unsigned len, unsigned limit)<br />
{<br />
	union {<br />
		unsigned char __buf[DLM_INBUF_LEN];<br />
		/* this is to force proper alignment on some arches */<br />
		union dlm_packet p;<br />
	} __tmp;<br />
	union dlm_packet *p = &#038;__tmp.p;<br />
	int ret = 0;<br />
	int err = 0;<br />
	uint16_t msglen;<br />
	uint32_t lockspace;</p>
<p>	while (len > sizeof(struct dlm_header)) {</p>
<p>		/* Copy just the header to check the total length.  The<br />
		   message may wrap around the end of the buffer back to the<br />
		   start, so we need to use a temp buffer and copy_from_cb. */</p>
<p>		copy_from_cb(p, base, offset, sizeof(struct dlm_header),<br />
			     limit);</p>
<p>		msglen = le16_to_cpu(p->header.h_length);<br />
		lockspace = p->header.h_lockspace;</p>
<p>		err = -EINVAL;<br />
		if (msglen < sizeof(struct dlm_header))<br />
			break;<br />
		if (p->header.h_cmd == DLM_MSG) {<br />
			if (msglen < sizeof(struct dlm_message))<br />
				break;<br />
		} else {<br />
			if (msglen < sizeof(struct dlm_rcom))<br />
				break;<br />
		}<br />
		err = -E2BIG;<br />
		if (msglen > dlm_config.ci_buffer_size) {<br />
			log_print(&raquo;message size %d from %d too big, buf len %d&raquo;,<br />
				  msglen, nodeid, len);<br />
			break;<br />
		}<br />
		err = 0;</p>
<p>		/* If only part of the full message is contained in this<br />
		   buffer, then do nothing and wait for lowcomms to call<br />
		   us again later with more data.  We return 0 meaning<br />
		   we&#8217;ve consumed none of the input buffer. */</p>
<p>		if (msglen > len)<br />
			break;</p>
<p>		/* Allocate a larger temp buffer if the full message won&#8217;t fit<br />
		   in the buffer on the stack (which should work for most<br />
		   ordinary messages). */</p>
<p>		if (msglen > sizeof(__tmp) &#038;&#038; p == &#038;__tmp.p) {<br />
			p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS);<br />
			if (p == NULL)<br />
				return ret;<br />
		}</p>
<p>		copy_from_cb(p, base, offset, msglen, limit);</p>
<p>		BUG_ON(lockspace != p->header.h_lockspace);</p>
<p>		ret += msglen;<br />
		offset += msglen;<br />
		offset &#038;= (limit &#8211; 1);<br />
		len -= msglen;</p>
<p>		dlm_receive_buffer(p, nodeid);<br />
	}</p>
<p>	if (p != &#038;__tmp.p)<br />
		kfree(p);</p>
<p>	return err ? err : ret;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/midcomms-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>member.h</title>
		<link>http://lynyrd.ru/member-h-2</link>
		<comments>http://lynyrd.ru/member-h-2#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:54:05 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/member-h-2</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2007 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1052"></span><br />
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __MEMORY_DOT_H__<br />
#define __MEMORY_DOT_H__</p>
<p>int dlm_memory_init(void);<br />
void dlm_memory_exit(void);<br />
struct dlm_rsb *dlm_allocate_rsb(struct dlm_ls *ls, int namelen);<br />
void dlm_free_rsb(struct dlm_rsb *r);<br />
struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls);<br />
void dlm_free_lkb(struct dlm_lkb *l);<br />
char *dlm_allocate_lvb(struct dlm_ls *ls);<br />
void dlm_free_lvb(char *l);</p>
<p>#endif		/* __MEMORY_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/member-h-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>memory.c</title>
		<link>http://lynyrd.ru/memory-c</link>
		<comments>http://lynyrd.ru/memory-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:53:48 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1050</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2007 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1050"></span><br />
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;memory.h&raquo;</p>
<p>static struct kmem_cache *lkb_cache;</p>
<p>int __init dlm_memory_init(void)<br />
{<br />
	int ret = 0;</p>
<p>	lkb_cache = kmem_cache_create(&raquo;dlm_lkb&raquo;, sizeof(struct dlm_lkb),<br />
				__alignof__(struct dlm_lkb), 0, NULL);<br />
	if (!lkb_cache)<br />
		ret = -ENOMEM;<br />
	return ret;<br />
}</p>
<p>void dlm_memory_exit(void)<br />
{<br />
	if (lkb_cache)<br />
		kmem_cache_destroy(lkb_cache);<br />
}</p>
<p>char *dlm_allocate_lvb(struct dlm_ls *ls)<br />
{<br />
	char *p;</p>
<p>	p = kzalloc(ls->ls_lvblen, ls->ls_allocation);<br />
	return p;<br />
}</p>
<p>void dlm_free_lvb(char *p)<br />
{<br />
	kfree(p);<br />
}</p>
<p>/* FIXME: have some minimal space built-in to rsb for the name and<br />
   kmalloc a separate name if needed, like dentries are done */</p>
<p>struct dlm_rsb *dlm_allocate_rsb(struct dlm_ls *ls, int namelen)<br />
{<br />
	struct dlm_rsb *r;</p>
<p>	DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);</p>
<p>	r = kzalloc(sizeof(*r) + namelen, ls->ls_allocation);<br />
	return r;<br />
}</p>
<p>void dlm_free_rsb(struct dlm_rsb *r)<br />
{<br />
	if (r->res_lvbptr)<br />
		dlm_free_lvb(r->res_lvbptr);<br />
	kfree(r);<br />
}</p>
<p>struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	lkb = kmem_cache_zalloc(lkb_cache, ls->ls_allocation);<br />
	return lkb;<br />
}</p>
<p>void dlm_free_lkb(struct dlm_lkb *lkb)<br />
{<br />
	if (lkb->lkb_flags &#038; DLM_IFL_USER) {<br />
		struct dlm_user_args *ua;<br />
		ua = lkb->lkb_ua;<br />
		if (ua) {<br />
			if (ua->lksb.sb_lvbptr)<br />
				kfree(ua->lksb.sb_lvbptr);<br />
			kfree(ua);<br />
		}<br />
	}<br />
	kmem_cache_free(lkb_cache, lkb);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/memory-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>member.h</title>
		<link>http://lynyrd.ru/member-h</link>
		<comments>http://lynyrd.ru/member-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:53:31 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/member-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2008 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 __MEMBER_DOT_H__
#define __MEMBER_DOT_H__
int dlm_ls_stop(struct dlm_ls *ls);
int dlm_ls_start(struct dlm_ls *ls);
void dlm_clear_members(struct dlm_ls *ls);
void ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.<span id="more-1049"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __MEMBER_DOT_H__<br />
#define __MEMBER_DOT_H__</p>
<p>int dlm_ls_stop(struct dlm_ls *ls);<br />
int dlm_ls_start(struct dlm_ls *ls);<br />
void dlm_clear_members(struct dlm_ls *ls);<br />
void dlm_clear_members_gone(struct dlm_ls *ls);<br />
int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);<br />
int dlm_is_removed(struct dlm_ls *ls, int nodeid);<br />
int dlm_is_member(struct dlm_ls *ls, int nodeid);</p>
<p>#endif                          /* __MEMBER_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/member-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>member.c</title>
		<link>http://lynyrd.ru/member-c</link>
		<comments>http://lynyrd.ru/member-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:53:14 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1047</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2009 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 &#171;dlm_internal.h&#187;
#include &#171;lockspace.h&#187;
#include &#171;member.h&#187;
#include &#171;recoverd.h&#187;
#include &#171;recover.h&#187;
#include &#171;rcom.h&#187;
#include &#171;config.h&#187;
#include &#171;lowcomms.h&#187;
static void add_ordered_member(struct dlm_ls ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.<span id="more-1047"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;recoverd.h&raquo;<br />
#include &laquo;recover.h&raquo;<br />
#include &laquo;rcom.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;</p>
<p>static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)<br />
{<br />
	struct dlm_member *memb = NULL;<br />
	struct list_head *tmp;<br />
	struct list_head *newlist = &#038;new->list;<br />
	struct list_head *head = &#038;ls->ls_nodes;</p>
<p>	list_for_each(tmp, head) {<br />
		memb = list_entry(tmp, struct dlm_member, list);<br />
		if (new->nodeid < memb->nodeid)<br />
			break;<br />
	}</p>
<p>	if (!memb)<br />
		list_add_tail(newlist, head);<br />
	else {<br />
		/* FIXME: can use list macro here */<br />
		newlist->prev = tmp->prev;<br />
		newlist->next = tmp;<br />
		tmp->prev->next = newlist;<br />
		tmp->prev = newlist;<br />
	}<br />
}</p>
<p>static int dlm_add_member(struct dlm_ls *ls, int nodeid)<br />
{<br />
	struct dlm_member *memb;<br />
	int w, error;</p>
<p>	memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);<br />
	if (!memb)<br />
		return -ENOMEM;</p>
<p>	w = dlm_node_weight(ls->ls_name, nodeid);<br />
	if (w < 0) {<br />
		kfree(memb);<br />
		return w;<br />
	}</p>
<p>	error = dlm_lowcomms_connect_node(nodeid);<br />
	if (error < 0) {<br />
		kfree(memb);<br />
		return error;<br />
	}</p>
<p>	memb->nodeid = nodeid;<br />
	memb->weight = w;<br />
	add_ordered_member(ls, memb);<br />
	ls->ls_num_nodes++;<br />
	return 0;<br />
}</p>
<p>static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)<br />
{<br />
	list_move(&#038;memb->list, &#038;ls->ls_nodes_gone);<br />
	ls->ls_num_nodes&#8211;;<br />
}</p>
<p>int dlm_is_member(struct dlm_ls *ls, int nodeid)<br />
{<br />
	struct dlm_member *memb;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		if (memb->nodeid == nodeid)<br />
			return 1;<br />
	}<br />
	return 0;<br />
}</p>
<p>int dlm_is_removed(struct dlm_ls *ls, int nodeid)<br />
{<br />
	struct dlm_member *memb;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes_gone, list) {<br />
		if (memb->nodeid == nodeid)<br />
			return 1;<br />
	}<br />
	return 0;<br />
}</p>
<p>static void clear_memb_list(struct list_head *head)<br />
{<br />
	struct dlm_member *memb;</p>
<p>	while (!list_empty(head)) {<br />
		memb = list_entry(head->next, struct dlm_member, list);<br />
		list_del(&#038;memb->list);<br />
		kfree(memb);<br />
	}<br />
}</p>
<p>void dlm_clear_members(struct dlm_ls *ls)<br />
{<br />
	clear_memb_list(&#038;ls->ls_nodes);<br />
	ls->ls_num_nodes = 0;<br />
}</p>
<p>void dlm_clear_members_gone(struct dlm_ls *ls)<br />
{<br />
	clear_memb_list(&#038;ls->ls_nodes_gone);<br />
}</p>
<p>static void make_member_array(struct dlm_ls *ls)<br />
{<br />
	struct dlm_member *memb;<br />
	int i, w, x = 0, total = 0, all_zero = 0, *array;</p>
<p>	kfree(ls->ls_node_array);<br />
	ls->ls_node_array = NULL;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		if (memb->weight)<br />
			total += memb->weight;<br />
	}</p>
<p>	/* all nodes revert to weight of 1 if all have weight 0 */</p>
<p>	if (!total) {<br />
		total = ls->ls_num_nodes;<br />
		all_zero = 1;<br />
	}</p>
<p>	ls->ls_total_weight = total;</p>
<p>	array = kmalloc(sizeof(int) * total, ls->ls_allocation);<br />
	if (!array)<br />
		return;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		if (!all_zero &#038;&#038; !memb->weight)<br />
			continue;</p>
<p>		if (all_zero)<br />
			w = 1;<br />
		else<br />
			w = memb->weight;</p>
<p>		DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););</p>
<p>		for (i = 0; i < w; i++)<br />
			array[x++] = memb->nodeid;<br />
	}</p>
<p>	ls->ls_node_array = array;<br />
}</p>
<p>/* send a status request to all members just to establish comms connections */</p>
<p>static int ping_members(struct dlm_ls *ls)<br />
{<br />
	struct dlm_member *memb;<br />
	int error = 0;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		error = dlm_recovery_stopped(ls);<br />
		if (error)<br />
			break;<br />
		error = dlm_rcom_status(ls, memb->nodeid);<br />
		if (error)<br />
			break;<br />
	}<br />
	if (error)<br />
		log_debug(ls, &laquo;ping_members aborted %d last nodeid %d&raquo;,<br />
			  error, ls->ls_recover_nodeid);<br />
	return error;<br />
}</p>
<p>int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)<br />
{<br />
	struct dlm_member *memb, *safe;<br />
	int i, error, found, pos = 0, neg = 0, low = -1;</p>
<p>	/* previously removed members that we&#8217;ve not finished removing need to<br />
	   count as a negative change so the &laquo;neg&raquo; recovery steps will happen */</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes_gone, list) {<br />
		log_debug(ls, &laquo;prev removed member %d&raquo;, memb->nodeid);<br />
		neg++;<br />
	}</p>
<p>	/* move departed members from ls_nodes to ls_nodes_gone */</p>
<p>	list_for_each_entry_safe(memb, safe, &#038;ls->ls_nodes, list) {<br />
		found = 0;<br />
		for (i = 0; i < rv->node_count; i++) {<br />
			if (memb->nodeid == rv->nodeids[i]) {<br />
				found = 1;<br />
				break;<br />
			}<br />
		}</p>
<p>		if (!found) {<br />
			neg++;<br />
			dlm_remove_member(ls, memb);<br />
			log_debug(ls, &laquo;remove member %d&raquo;, memb->nodeid);<br />
		}<br />
	}</p>
<p>	/* Add an entry to ls_nodes_gone for members that were removed and<br />
	   then added again, so that previous state for these nodes will be<br />
	   cleared during recovery. */</p>
<p>	for (i = 0; i < rv->new_count; i++) {<br />
		if (!dlm_is_member(ls, rv->new[i]))<br />
			continue;<br />
		log_debug(ls, &laquo;new nodeid %d is a re-added member&raquo;, rv->new[i]);</p>
<p>		memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);<br />
		if (!memb)<br />
			return -ENOMEM;<br />
		memb->nodeid = rv->new[i];<br />
		list_add_tail(&#038;memb->list, &#038;ls->ls_nodes_gone);<br />
		neg++;<br />
	}</p>
<p>	/* add new members to ls_nodes */</p>
<p>	for (i = 0; i < rv->node_count; i++) {<br />
		if (dlm_is_member(ls, rv->nodeids[i]))<br />
			continue;<br />
		dlm_add_member(ls, rv->nodeids[i]);<br />
		pos++;<br />
		log_debug(ls, &laquo;add member %d&raquo;, rv->nodeids[i]);<br />
	}</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		if (low == -1 || memb->nodeid < low)<br />
			low = memb->nodeid;<br />
	}<br />
	ls->ls_low_nodeid = low;</p>
<p>	make_member_array(ls);<br />
	dlm_set_recover_status(ls, DLM_RS_NODES);<br />
	*neg_out = neg;</p>
<p>	error = ping_members(ls);<br />
	if (!error || error == -EPROTO) {<br />
		/* new_lockspace() may be waiting to know if the config<br />
		   is good or bad */<br />
		ls->ls_members_result = error;<br />
		complete(&#038;ls->ls_members_done);<br />
	}<br />
	if (error)<br />
		goto out;</p>
<p>	error = dlm_recover_members_wait(ls);<br />
 out:<br />
	log_debug(ls, &laquo;total members %d error %d&raquo;, ls->ls_num_nodes, error);<br />
	return error;<br />
}</p>
<p>/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before<br />
   dlm_ls_start() is called on any of them to start the new recovery. */</p>
<p>int dlm_ls_stop(struct dlm_ls *ls)<br />
{<br />
	int new;</p>
<p>	/*<br />
	 * Prevent dlm_recv from being in the middle of something when we do<br />
	 * the stop.  This includes ensuring dlm_recv isn&#8217;t processing a<br />
	 * recovery message (rcom), while dlm_recoverd is aborting and<br />
	 * resetting things from an in-progress recovery.  i.e. we want<br />
	 * dlm_recoverd to abort its recovery without worrying about dlm_recv<br />
	 * processing an rcom at the same time.  Stopping dlm_recv also makes<br />
	 * it easy for dlm_receive_message() to check locking stopped and add a<br />
	 * message to the requestqueue without races.<br />
	 */</p>
<p>	down_write(&#038;ls->ls_recv_active);</p>
<p>	/*<br />
	 * Abort any recovery that&#8217;s in progress (see RECOVERY_STOP,<br />
	 * dlm_recovery_stopped()) and tell any other threads running in the<br />
	 * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).<br />
	 */</p>
<p>	spin_lock(&#038;ls->ls_recover_lock);<br />
	set_bit(LSFL_RECOVERY_STOP, &#038;ls->ls_flags);<br />
	new = test_and_clear_bit(LSFL_RUNNING, &#038;ls->ls_flags);<br />
	ls->ls_recover_seq++;<br />
	spin_unlock(&#038;ls->ls_recover_lock);</p>
<p>	/*<br />
	 * Let dlm_recv run again, now any normal messages will be saved on the<br />
	 * requestqueue for later.<br />
	 */</p>
<p>	up_write(&#038;ls->ls_recv_active);</p>
<p>	/*<br />
	 * This in_recovery lock does two things:<br />
	 * 1) Keeps this function from returning until all threads are out<br />
	 *    of locking routines and locking is truely stopped.<br />
	 * 2) Keeps any new requests from being processed until it&#8217;s unlocked<br />
	 *    when recovery is complete.<br />
	 */</p>
<p>	if (new)<br />
		down_write(&#038;ls->ls_in_recovery);</p>
<p>	/*<br />
	 * The recoverd suspend/resume makes sure that dlm_recoverd (if<br />
	 * running) has noticed RECOVERY_STOP above and quit processing the<br />
	 * previous recovery.<br />
	 */</p>
<p>	dlm_recoverd_suspend(ls);<br />
	ls->ls_recover_status = 0;<br />
	dlm_recoverd_resume(ls);</p>
<p>	if (!ls->ls_recover_begin)<br />
		ls->ls_recover_begin = jiffies;<br />
	return 0;<br />
}</p>
<p>int dlm_ls_start(struct dlm_ls *ls)<br />
{<br />
	struct dlm_recover *rv = NULL, *rv_old;<br />
	int *ids = NULL, *new = NULL;<br />
	int error, ids_count = 0, new_count = 0;</p>
<p>	rv = kzalloc(sizeof(struct dlm_recover), ls->ls_allocation);<br />
	if (!rv)<br />
		return -ENOMEM;</p>
<p>	error = dlm_nodeid_list(ls->ls_name, &#038;ids, &#038;ids_count,<br />
				&#038;new, &#038;new_count);<br />
	if (error < 0)<br />
		goto fail;</p>
<p>	spin_lock(&#038;ls->ls_recover_lock);</p>
<p>	/* the lockspace needs to be stopped before it can be started */</p>
<p>	if (!dlm_locking_stopped(ls)) {<br />
		spin_unlock(&#038;ls->ls_recover_lock);<br />
		log_error(ls, &laquo;start ignored: lockspace running&raquo;);<br />
		error = -EINVAL;<br />
		goto fail;<br />
	}</p>
<p>	rv->nodeids = ids;<br />
	rv->node_count = ids_count;<br />
	rv->new = new;<br />
	rv->new_count = new_count;<br />
	rv->seq = ++ls->ls_recover_seq;<br />
	rv_old = ls->ls_recover_args;<br />
	ls->ls_recover_args = rv;<br />
	spin_unlock(&#038;ls->ls_recover_lock);</p>
<p>	if (rv_old) {<br />
		log_error(ls, &laquo;unused recovery %llx %d&raquo;,<br />
			  (unsigned long long)rv_old->seq, rv_old->node_count);<br />
		kfree(rv_old->nodeids);<br />
		kfree(rv_old->new);<br />
		kfree(rv_old);<br />
	}</p>
<p>	dlm_recoverd_kick(ls);<br />
	return 0;</p>
<p> fail:<br />
	kfree(rv);<br />
	kfree(ids);<br />
	kfree(new);<br />
	return error;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/member-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Makefile</title>
		<link>http://lynyrd.ru/makefile-13</link>
		<comments>http://lynyrd.ru/makefile-13#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:52:44 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1045</guid>
		<description><![CDATA[obj-$(CONFIG_DLM) +=		dlm.o
dlm-y :=			ast.o \
				config.o \
				dir.o \
				lock.o \
				lockspace.o \
				main.o \
				member.o \
				memory.o \
				midcomms.o \
				netlink.o \
				lowcomms.o \
				plock.o \
				rcom.o \
				recover.o \
				recoverd.o \
				requestqueue.o \
				user.o \
				util.o
dlm-$(CONFIG_DLM_DEBUG) +=	debug_fs.o
]]></description>
			<content:encoded><![CDATA[<p>obj-$(CONFIG_DLM) +=		dlm.o<br />
dlm-y :=			ast.o \<span id="more-1045"></span><br />
				config.o \<br />
				dir.o \<br />
				lock.o \<br />
				lockspace.o \<br />
				main.o \<br />
				member.o \<br />
				memory.o \<br />
				midcomms.o \<br />
				netlink.o \<br />
				lowcomms.o \<br />
				plock.o \<br />
				rcom.o \<br />
				recover.o \<br />
				recoverd.o \<br />
				requestqueue.o \<br />
				user.o \<br />
				util.o<br />
dlm-$(CONFIG_DLM_DEBUG) +=	debug_fs.o</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/makefile-13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>main.c</title>
		<link>http://lynyrd.ru/main-c-2</link>
		<comments>http://lynyrd.ru/main-c-2#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:52:23 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1043</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2007 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1043"></span><br />
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;user.h&raquo;<br />
#include &laquo;memory.h&raquo;<br />
#include &laquo;config.h&raquo;</p>
<p>static int __init init_dlm(void)<br />
{<br />
	int error;</p>
<p>	error = dlm_memory_init();<br />
	if (error)<br />
		goto out;</p>
<p>	error = dlm_lockspace_init();<br />
	if (error)<br />
		goto out_mem;</p>
<p>	error = dlm_config_init();<br />
	if (error)<br />
		goto out_lockspace;</p>
<p>	error = dlm_register_debugfs();<br />
	if (error)<br />
		goto out_config;</p>
<p>	error = dlm_user_init();<br />
	if (error)<br />
		goto out_debug;</p>
<p>	error = dlm_netlink_init();<br />
	if (error)<br />
		goto out_user;</p>
<p>	error = dlm_plock_init();<br />
	if (error)<br />
		goto out_netlink;</p>
<p>	printk(&raquo;DLM (built %s %s) installed\n&raquo;, __DATE__, __TIME__);</p>
<p>	return 0;</p>
<p> out_netlink:<br />
	dlm_netlink_exit();<br />
 out_user:<br />
	dlm_user_exit();<br />
 out_debug:<br />
	dlm_unregister_debugfs();<br />
 out_config:<br />
	dlm_config_exit();<br />
 out_lockspace:<br />
	dlm_lockspace_exit();<br />
 out_mem:<br />
	dlm_memory_exit();<br />
 out:<br />
	return error;<br />
}</p>
<p>static void __exit exit_dlm(void)<br />
{<br />
	dlm_plock_exit();<br />
	dlm_netlink_exit();<br />
	dlm_user_exit();<br />
	dlm_config_exit();<br />
	dlm_memory_exit();<br />
	dlm_lockspace_exit();<br />
	dlm_unregister_debugfs();<br />
}</p>
<p>module_init(init_dlm);<br />
module_exit(exit_dlm);</p>
<p>MODULE_DESCRIPTION(&raquo;Distributed Lock Manager&raquo;);<br />
MODULE_AUTHOR(&raquo;Red Hat, Inc.&raquo;);<br />
MODULE_LICENSE(&raquo;GPL&raquo;);</p>
<p>EXPORT_SYMBOL_GPL(dlm_new_lockspace);<br />
EXPORT_SYMBOL_GPL(dlm_release_lockspace);<br />
EXPORT_SYMBOL_GPL(dlm_lock);<br />
EXPORT_SYMBOL_GPL(dlm_unlock);</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/main-c-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lvb_table.h</title>
		<link>http://lynyrd.ru/lvb_table-h</link>
		<comments>http://lynyrd.ru/lvb_table-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:52:06 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1041</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#ifndef __LVB_TABLE_DOT_H__
#define __LVB_TABLE_DOT_H__
extern const int dlm_lvb_operations[8][8];
#endif
]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.<span id="more-1041"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __LVB_TABLE_DOT_H__<br />
#define __LVB_TABLE_DOT_H__</p>
<p>extern const int dlm_lvb_operations[8][8];</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lvb_table-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lowcomms.h</title>
		<link>http://lynyrd.ru/lowcomms-h</link>
		<comments>http://lynyrd.ru/lowcomms-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:51:43 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1039</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2009 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1039"></span><br />
**  Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __LOWCOMMS_DOT_H__<br />
#define __LOWCOMMS_DOT_H__</p>
<p>int dlm_lowcomms_start(void);<br />
void dlm_lowcomms_stop(void);<br />
int dlm_lowcomms_close(int nodeid);<br />
void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);<br />
void dlm_lowcomms_commit_buffer(void *mh);<br />
int dlm_lowcomms_connect_node(int nodeid);</p>
<p>#endif				/* __LOWCOMMS_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lowcomms-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lowcomms.c</title>
		<link>http://lynyrd.ru/lowcomms-c</link>
		<comments>http://lynyrd.ru/lowcomms-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:51:27 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/lowcomms-c</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2009 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1038"></span><br />
**  Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>/*<br />
 * lowcomms.c<br />
 *<br />
 * This is the &laquo;low-level&raquo; comms layer.<br />
 *<br />
 * It is responsible for sending/receiving messages<br />
 * from other nodes in the cluster.<br />
 *<br />
 * Cluster nodes are referred to by their nodeids. nodeids are<br />
 * simply 32 bit numbers to the locking module &#8211; if they need to<br />
 * be expanded for the cluster infrastructure then that is its<br />
 * responsibility. It is this layer&#8217;s<br />
 * responsibility to resolve these into IP address or<br />
 * whatever it needs for inter-node communication.<br />
 *<br />
 * The comms level is two kernel threads that deal mainly with<br />
 * the receiving of messages from other nodes and passing them<br />
 * up to the mid-level comms layer (which understands the<br />
 * message format) for execution by the locking core, and<br />
 * a send thread which does all the setting up of connections<br />
 * to remote nodes and the sending of data. Threads are not allowed<br />
 * to send their own data because it may cause them to wait in times<br />
 * of high load. Also, this way, the sending thread can collect together<br />
 * messages bound for one node and send them in one block.<br />
 *<br />
 * lowcomms will choose to use either TCP or SCTP as its transport layer<br />
 * depending on the configuration variable &#8216;protocol&#8217;. This should be set<br />
 * to 0 (default) for TCP or 1 for SCTP. It should be configured using a<br />
 * cluster-wide mechanism as it must be the same on all nodes of the cluster<br />
 * for the DLM to function.<br />
 *<br />
 */</p>
<p>#include <asm/ioctls.h><br />
#include <net/sock.h><br />
#include <net/tcp.h><br />
#include
<linux/pagemap.h>
#include
<linux/file.h>
#include
<linux/mutex.h>
#include
<linux/sctp.h>
#include <net/sctp/user.h><br />
#include <net/ipv6.h></p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;midcomms.h&raquo;<br />
#include &laquo;config.h&raquo;</p>
<p>#define NEEDED_RMEM (4*1024*1024)<br />
#define CONN_HASH_SIZE 32</p>
<p>struct cbuf {<br />
	unsigned int base;<br />
	unsigned int len;<br />
	unsigned int mask;<br />
};</p>
<p>static void cbuf_add(struct cbuf *cb, int n)<br />
{<br />
	cb->len += n;<br />
}</p>
<p>static int cbuf_data(struct cbuf *cb)<br />
{<br />
	return ((cb->base + cb->len) &#038; cb->mask);<br />
}</p>
<p>static void cbuf_init(struct cbuf *cb, int size)<br />
{<br />
	cb->base = cb->len = 0;<br />
	cb->mask = size-1;<br />
}</p>
<p>static void cbuf_eat(struct cbuf *cb, int n)<br />
{<br />
	cb->len  -= n;<br />
	cb->base += n;<br />
	cb->base &#038;= cb->mask;<br />
}</p>
<p>static bool cbuf_empty(struct cbuf *cb)<br />
{<br />
	return cb->len == 0;<br />
}</p>
<p>struct connection {<br />
	struct socket *sock;	/* NULL if not connected */<br />
	uint32_t nodeid;	/* So we know who we are in the list */<br />
	struct mutex sock_mutex;<br />
	unsigned long flags;<br />
#define CF_READ_PENDING 1<br />
#define CF_WRITE_PENDING 2<br />
#define CF_CONNECT_PENDING 3<br />
#define CF_INIT_PENDING 4<br />
#define CF_IS_OTHERCON 5<br />
#define CF_CLOSE 6<br />
	struct list_head writequeue;  /* List of outgoing writequeue_entries */<br />
	spinlock_t writequeue_lock;<br />
	int (*rx_action) (struct connection *);	/* What to do when active */<br />
	void (*connect_action) (struct connection *);	/* What to do to connect */<br />
	struct page *rx_page;<br />
	struct cbuf cb;<br />
	int retries;<br />
#define MAX_CONNECT_RETRIES 3<br />
	int sctp_assoc;<br />
	struct hlist_node list;<br />
	struct connection *othercon;<br />
	struct work_struct rwork; /* Receive workqueue */<br />
	struct work_struct swork; /* Send workqueue */<br />
};<br />
#define sock2con(x) ((struct connection *)(x)->sk_user_data)</p>
<p>/* An entry waiting to be sent */<br />
struct writequeue_entry {<br />
	struct list_head list;<br />
	struct page *page;<br />
	int offset;<br />
	int len;<br />
	int end;<br />
	int users;<br />
	struct connection *con;<br />
};</p>
<p>static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];<br />
static int dlm_local_count;</p>
<p>/* Work queues */<br />
static struct workqueue_struct *recv_workqueue;<br />
static struct workqueue_struct *send_workqueue;</p>
<p>static struct hlist_head connection_hash[CONN_HASH_SIZE];<br />
static DEFINE_MUTEX(connections_lock);<br />
static struct kmem_cache *con_cache;</p>
<p>static void process_recv_sockets(struct work_struct *work);<br />
static void process_send_sockets(struct work_struct *work);</p>
<p>/* This is deliberately very simple because most clusters have simple<br />
   sequential nodeids, so we should be able to go straight to a connection<br />
   struct in the array */<br />
static inline int nodeid_hash(int nodeid)<br />
{<br />
	return nodeid &#038; (CONN_HASH_SIZE-1);<br />
}</p>
<p>static struct connection *__find_con(int nodeid)<br />
{<br />
	int r;<br />
	struct hlist_node *h;<br />
	struct connection *con;</p>
<p>	r = nodeid_hash(nodeid);</p>
<p>	hlist_for_each_entry(con, h, &#038;connection_hash[r], list) {<br />
		if (con->nodeid == nodeid)<br />
			return con;<br />
	}<br />
	return NULL;<br />
}</p>
<p>/*<br />
 * If &#8216;allocation&#8217; is zero then we don&#8217;t attempt to create a new<br />
 * connection structure for this node.<br />
 */<br />
static struct connection *__nodeid2con(int nodeid, gfp_t alloc)<br />
{<br />
	struct connection *con = NULL;<br />
	int r;</p>
<p>	con = __find_con(nodeid);<br />
	if (con || !alloc)<br />
		return con;</p>
<p>	con = kmem_cache_zalloc(con_cache, alloc);<br />
	if (!con)<br />
		return NULL;</p>
<p>	r = nodeid_hash(nodeid);<br />
	hlist_add_head(&#038;con->list, &#038;connection_hash[r]);</p>
<p>	con->nodeid = nodeid;<br />
	mutex_init(&#038;con->sock_mutex);<br />
	INIT_LIST_HEAD(&#038;con->writequeue);<br />
	spin_lock_init(&#038;con->writequeue_lock);<br />
	INIT_WORK(&#038;con->swork, process_send_sockets);<br />
	INIT_WORK(&#038;con->rwork, process_recv_sockets);</p>
<p>	/* Setup action pointers for child sockets */<br />
	if (con->nodeid) {<br />
		struct connection *zerocon = __find_con(0);</p>
<p>		con->connect_action = zerocon->connect_action;<br />
		if (!con->rx_action)<br />
			con->rx_action = zerocon->rx_action;<br />
	}</p>
<p>	return con;<br />
}</p>
<p>/* Loop round all connections */<br />
static void foreach_conn(void (*conn_func)(struct connection *c))<br />
{<br />
	int i;<br />
	struct hlist_node *h, *n;<br />
	struct connection *con;</p>
<p>	for (i = 0; i < CONN_HASH_SIZE; i++) {<br />
		hlist_for_each_entry_safe(con, h, n, &#038;connection_hash[i], list){<br />
			conn_func(con);<br />
		}<br />
	}<br />
}</p>
<p>static struct connection *nodeid2con(int nodeid, gfp_t allocation)<br />
{<br />
	struct connection *con;</p>
<p>	mutex_lock(&#038;connections_lock);<br />
	con = __nodeid2con(nodeid, allocation);<br />
	mutex_unlock(&#038;connections_lock);</p>
<p>	return con;<br />
}</p>
<p>/* This is a bit drastic, but only called when things go wrong */<br />
static struct connection *assoc2con(int assoc_id)<br />
{<br />
	int i;<br />
	struct hlist_node *h;<br />
	struct connection *con;</p>
<p>	mutex_lock(&#038;connections_lock);</p>
<p>	for (i = 0 ; i < CONN_HASH_SIZE; i++) {<br />
		hlist_for_each_entry(con, h, &#038;connection_hash[i], list) {<br />
			if (con &#038;&#038; con->sctp_assoc == assoc_id) {<br />
				mutex_unlock(&#038;connections_lock);<br />
				return con;<br />
			}<br />
		}<br />
	}<br />
	mutex_unlock(&#038;connections_lock);<br />
	return NULL;<br />
}</p>
<p>static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)<br />
{<br />
	struct sockaddr_storage addr;<br />
	int error;</p>
<p>	if (!dlm_local_count)<br />
		return -1;</p>
<p>	error = dlm_nodeid_to_addr(nodeid, &#038;addr);<br />
	if (error)<br />
		return error;</p>
<p>	if (dlm_local_addr[0]->ss_family == AF_INET) {<br />
		struct sockaddr_in *in4  = (struct sockaddr_in *) &addr;<br />
		struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;<br />
		ret4->sin_addr.s_addr = in4->sin_addr.s_addr;<br />
	} else {<br />
		struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;<br />
		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;<br />
		ipv6_addr_copy(&#038;ret6->sin6_addr, &#038;in6->sin6_addr);<br />
	}</p>
<p>	return 0;<br />
}</p>
<p>/* Data available on socket or listen socket received a connect */<br />
static void lowcomms_data_ready(struct sock *sk, int count_unused)<br />
{<br />
	struct connection *con = sock2con(sk);<br />
	if (con &#038;&#038; !test_and_set_bit(CF_READ_PENDING, &#038;con->flags))<br />
		queue_work(recv_workqueue, &#038;con->rwork);<br />
}</p>
<p>static void lowcomms_write_space(struct sock *sk)<br />
{<br />
	struct connection *con = sock2con(sk);</p>
<p>	if (con &#038;&#038; !test_and_set_bit(CF_WRITE_PENDING, &#038;con->flags))<br />
		queue_work(send_workqueue, &#038;con->swork);<br />
}</p>
<p>static inline void lowcomms_connect_sock(struct connection *con)<br />
{<br />
	if (test_bit(CF_CLOSE, &#038;con->flags))<br />
		return;<br />
	if (!test_and_set_bit(CF_CONNECT_PENDING, &#038;con->flags))<br />
		queue_work(send_workqueue, &#038;con->swork);<br />
}</p>
<p>static void lowcomms_state_change(struct sock *sk)<br />
{<br />
	if (sk->sk_state == TCP_ESTABLISHED)<br />
		lowcomms_write_space(sk);<br />
}</p>
<p>int dlm_lowcomms_connect_node(int nodeid)<br />
{<br />
	struct connection *con;</p>
<p>	/* with sctp there&#8217;s no connecting without sending */<br />
	if (dlm_config.ci_protocol != 0)<br />
		return 0;</p>
<p>	if (nodeid == dlm_our_nodeid())<br />
		return 0;</p>
<p>	con = nodeid2con(nodeid, GFP_NOFS);<br />
	if (!con)<br />
		return -ENOMEM;<br />
	lowcomms_connect_sock(con);<br />
	return 0;<br />
}</p>
<p>/* Make a socket active */<br />
static int add_sock(struct socket *sock, struct connection *con)<br />
{<br />
	con->sock = sock;</p>
<p>	/* Install a data_ready callback */<br />
	con->sock->sk->sk_data_ready = lowcomms_data_ready;<br />
	con->sock->sk->sk_write_space = lowcomms_write_space;<br />
	con->sock->sk->sk_state_change = lowcomms_state_change;<br />
	con->sock->sk->sk_user_data = con;<br />
	con->sock->sk->sk_allocation = GFP_NOFS;<br />
	return 0;<br />
}</p>
<p>/* Add the port number to an IPv6 or 4 sockaddr and return the address<br />
   length */<br />
static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,<br />
			  int *addr_len)<br />
{<br />
	saddr->ss_family =  dlm_local_addr[0]->ss_family;<br />
	if (saddr->ss_family == AF_INET) {<br />
		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;<br />
		in4_addr->sin_port = cpu_to_be16(port);<br />
		*addr_len = sizeof(struct sockaddr_in);<br />
		memset(&#038;in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));<br />
	} else {<br />
		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;<br />
		in6_addr->sin6_port = cpu_to_be16(port);<br />
		*addr_len = sizeof(struct sockaddr_in6);<br />
	}<br />
	memset((char *)saddr + *addr_len, 0, sizeof(struct sockaddr_storage) &#8211; *addr_len);<br />
}</p>
<p>/* Close a remote connection and tidy up */<br />
static void close_connection(struct connection *con, bool and_other)<br />
{<br />
	mutex_lock(&#038;con->sock_mutex);</p>
<p>	if (con->sock) {<br />
		sock_release(con->sock);<br />
		con->sock = NULL;<br />
	}<br />
	if (con->othercon &#038;&#038; and_other) {<br />
		/* Will only re-enter once. */<br />
		close_connection(con->othercon, false);<br />
	}<br />
	if (con->rx_page) {<br />
		__free_page(con->rx_page);<br />
		con->rx_page = NULL;<br />
	}</p>
<p>	con->retries = 0;<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
}</p>
<p>/* We only send shutdown messages to nodes that are not part of the cluster */<br />
static void sctp_send_shutdown(sctp_assoc_t associd)<br />
{<br />
	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];<br />
	struct msghdr outmessage;<br />
	struct cmsghdr *cmsg;<br />
	struct sctp_sndrcvinfo *sinfo;<br />
	int ret;<br />
	struct connection *con;</p>
<p>	con = nodeid2con(0,0);<br />
	BUG_ON(con == NULL);</p>
<p>	outmessage.msg_name = NULL;<br />
	outmessage.msg_namelen = 0;<br />
	outmessage.msg_control = outcmsg;<br />
	outmessage.msg_controllen = sizeof(outcmsg);<br />
	outmessage.msg_flags = MSG_EOR;</p>
<p>	cmsg = CMSG_FIRSTHDR(&#038;outmessage);<br />
	cmsg->cmsg_level = IPPROTO_SCTP;<br />
	cmsg->cmsg_type = SCTP_SNDRCV;<br />
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));<br />
	outmessage.msg_controllen = cmsg->cmsg_len;<br />
	sinfo = CMSG_DATA(cmsg);<br />
	memset(sinfo, 0&#215;00, sizeof(struct sctp_sndrcvinfo));</p>
<p>	sinfo->sinfo_flags |= MSG_EOF;<br />
	sinfo->sinfo_assoc_id = associd;</p>
<p>	ret = kernel_sendmsg(con->sock, &#038;outmessage, NULL, 0, 0);</p>
<p>	if (ret != 0)<br />
		log_print(&raquo;send EOF to node failed: %d&raquo;, ret);<br />
}</p>
<p>static void sctp_init_failed_foreach(struct connection *con)<br />
{<br />
	con->sctp_assoc = 0;<br />
	if (test_and_clear_bit(CF_CONNECT_PENDING, &#038;con->flags)) {<br />
		if (!test_and_set_bit(CF_WRITE_PENDING, &#038;con->flags))<br />
			queue_work(send_workqueue, &#038;con->swork);<br />
	}<br />
}</p>
<p>/* INIT failed but we don&#8217;t know which node&#8230;<br />
   restart INIT on all pending nodes */<br />
static void sctp_init_failed(void)<br />
{<br />
	mutex_lock(&#038;connections_lock);</p>
<p>	foreach_conn(sctp_init_failed_foreach);</p>
<p>	mutex_unlock(&#038;connections_lock);<br />
}</p>
<p>/* Something happened to an association */<br />
static void process_sctp_notification(struct connection *con,<br />
				      struct msghdr *msg, char *buf)<br />
{<br />
	union sctp_notification *sn = (union sctp_notification *)buf;</p>
<p>	if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {<br />
		switch (sn->sn_assoc_change.sac_state) {</p>
<p>		case SCTP_COMM_UP:<br />
		case SCTP_RESTART:<br />
		{<br />
			/* Check that the new node is in the lockspace */<br />
			struct sctp_prim prim;<br />
			int nodeid;<br />
			int prim_len, ret;<br />
			int addr_len;<br />
			struct connection *new_con;<br />
			sctp_peeloff_arg_t parg;<br />
			int parglen = sizeof(parg);<br />
			int err;</p>
<p>			/*<br />
			 * We get this before any data for an association.<br />
			 * We verify that the node is in the cluster and<br />
			 * then peel off a socket for it.<br />
			 */<br />
			if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {<br />
				log_print("COMM_UP for invalid assoc ID %d",<br />
					 (int)sn->sn_assoc_change.sac_assoc_id);<br />
				sctp_init_failed();<br />
				return;<br />
			}<br />
			memset(&#038;prim, 0, sizeof(struct sctp_prim));<br />
			prim_len = sizeof(struct sctp_prim);<br />
			prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;</p>
<p>			ret = kernel_getsockopt(con->sock,<br />
						IPPROTO_SCTP,<br />
						SCTP_PRIMARY_ADDR,<br />
						(char*)&#038;prim,<br />
						&#038;prim_len);<br />
			if (ret < 0) {<br />
				log_print("getsockopt/sctp_primary_addr on "<br />
					  "new assoc %d failed : %d",<br />
					  (int)sn->sn_assoc_change.sac_assoc_id,<br />
					  ret);</p>
<p>				/* Retry INIT later */<br />
				new_con = assoc2con(sn->sn_assoc_change.sac_assoc_id);<br />
				if (new_con)<br />
					clear_bit(CF_CONNECT_PENDING, &#038;con->flags);<br />
				return;<br />
			}<br />
			make_sockaddr(&#038;prim.ssp_addr, 0, &#038;addr_len);<br />
			if (dlm_addr_to_nodeid(&#038;prim.ssp_addr, &#038;nodeid)) {<br />
				int i;<br />
				unsigned char *b=(unsigned char *)&#038;prim.ssp_addr;<br />
				log_print(&raquo;reject connect from unknown addr&raquo;);<br />
				for (i=0; i<sizeof(struct sockaddr_storage);i++)<br />
					printk("%02x ", b[i]);<br />
				printk("\n");<br />
				sctp_send_shutdown(prim.ssp_assoc_id);<br />
				return;<br />
			}</p>
<p>			new_con = nodeid2con(nodeid, GFP_NOFS);<br />
			if (!new_con)<br />
				return;</p>
<p>			/* Peel off a new sock */<br />
			parg.associd = sn->sn_assoc_change.sac_assoc_id;<br />
			ret = kernel_getsockopt(con->sock, IPPROTO_SCTP,<br />
						SCTP_SOCKOPT_PEELOFF,<br />
						(void *)&#038;parg, &#038;parglen);<br />
			if (ret < 0) {<br />
				log_print("Can't peel off a socket for "<br />
					  "connection %d to node %d: err=%d",<br />
					  parg.associd, nodeid, ret);<br />
				return;<br />
			}<br />
			new_con->sock = sockfd_lookup(parg.sd, &#038;err);<br />
			if (!new_con->sock) {<br />
				log_print(&raquo;sockfd_lookup error %d&raquo;, err);<br />
				return;<br />
			}<br />
			add_sock(new_con->sock, new_con);<br />
			sockfd_put(new_con->sock);</p>
<p>			log_print(&raquo;connecting to %d sctp association %d&raquo;,<br />
				 nodeid, (int)sn->sn_assoc_change.sac_assoc_id);</p>
<p>			/* Send any pending writes */<br />
			clear_bit(CF_CONNECT_PENDING, &#038;new_con->flags);<br />
			clear_bit(CF_INIT_PENDING, &#038;con->flags);<br />
			if (!test_and_set_bit(CF_WRITE_PENDING, &#038;new_con->flags)) {<br />
				queue_work(send_workqueue, &#038;new_con->swork);<br />
			}<br />
			if (!test_and_set_bit(CF_READ_PENDING, &#038;new_con->flags))<br />
				queue_work(recv_workqueue, &#038;new_con->rwork);<br />
		}<br />
		break;</p>
<p>		case SCTP_COMM_LOST:<br />
		case SCTP_SHUTDOWN_COMP:<br />
		{<br />
			con = assoc2con(sn->sn_assoc_change.sac_assoc_id);<br />
			if (con) {<br />
				con->sctp_assoc = 0;<br />
			}<br />
		}<br />
		break;</p>
<p>		/* We don&#8217;t know which INIT failed, so clear the PENDING flags<br />
		 * on them all.  if assoc_id is zero then it will then try<br />
		 * again */</p>
<p>		case SCTP_CANT_STR_ASSOC:<br />
		{<br />
			log_print(&raquo;Can&#8217;t start SCTP association &#8211; retrying&raquo;);<br />
			sctp_init_failed();<br />
		}<br />
		break;</p>
<p>		default:<br />
			log_print(&raquo;unexpected SCTP assoc change id=%d state=%d&raquo;,<br />
				  (int)sn->sn_assoc_change.sac_assoc_id,<br />
				  sn->sn_assoc_change.sac_state);<br />
		}<br />
	}<br />
}</p>
<p>/* Data received from remote end */<br />
static int receive_from_sock(struct connection *con)<br />
{<br />
	int ret = 0;<br />
	struct msghdr msg = {};<br />
	struct kvec iov[2];<br />
	unsigned len;<br />
	int r;<br />
	int call_again_soon = 0;<br />
	int nvec;<br />
	char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];</p>
<p>	mutex_lock(&#038;con->sock_mutex);</p>
<p>	if (con->sock == NULL) {<br />
		ret = -EAGAIN;<br />
		goto out_close;<br />
	}</p>
<p>	if (con->rx_page == NULL) {<br />
		/*<br />
		 * This doesn&#8217;t need to be atomic, but I think it should<br />
		 * improve performance if it is.<br />
		 */<br />
		con->rx_page = alloc_page(GFP_ATOMIC);<br />
		if (con->rx_page == NULL)<br />
			goto out_resched;<br />
		cbuf_init(&#038;con->cb, PAGE_CACHE_SIZE);<br />
	}</p>
<p>	/* Only SCTP needs these really */<br />
	memset(&#038;incmsg, 0, sizeof(incmsg));<br />
	msg.msg_control = incmsg;<br />
	msg.msg_controllen = sizeof(incmsg);</p>
<p>	/*<br />
	 * iov[0] is the bit of the circular buffer between the current end<br />
	 * point (cb.base + cb.len) and the end of the buffer.<br />
	 */<br />
	iov[0].iov_len = con->cb.base &#8211; cbuf_data(&#038;con->cb);<br />
	iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&#038;con->cb);<br />
	iov[1].iov_len = 0;<br />
	nvec = 1;</p>
<p>	/*<br />
	 * iov[1] is the bit of the circular buffer between the start of the<br />
	 * buffer and the start of the currently used section (cb.base)<br />
	 */<br />
	if (cbuf_data(&#038;con->cb) >= con->cb.base) {<br />
		iov[0].iov_len = PAGE_CACHE_SIZE &#8211; cbuf_data(&#038;con->cb);<br />
		iov[1].iov_len = con->cb.base;<br />
		iov[1].iov_base = page_address(con->rx_page);<br />
		nvec = 2;<br />
	}<br />
	len = iov[0].iov_len + iov[1].iov_len;</p>
<p>	r = ret = kernel_recvmsg(con->sock, &#038;msg, iov, nvec, len,<br />
			       MSG_DONTWAIT | MSG_NOSIGNAL);<br />
	if (ret <= 0)<br />
		goto out_close;</p>
<p>	/* Process SCTP notifications */<br />
	if (msg.msg_flags &#038; MSG_NOTIFICATION) {<br />
		msg.msg_control = incmsg;<br />
		msg.msg_controllen = sizeof(incmsg);</p>
<p>		process_sctp_notification(con, &#038;msg,<br />
				page_address(con->rx_page) + con->cb.base);<br />
		mutex_unlock(&#038;con->sock_mutex);<br />
		return 0;<br />
	}<br />
	BUG_ON(con->nodeid == 0);</p>
<p>	if (ret == len)<br />
		call_again_soon = 1;<br />
	cbuf_add(&#038;con->cb, ret);<br />
	ret = dlm_process_incoming_buffer(con->nodeid,<br />
					  page_address(con->rx_page),<br />
					  con->cb.base, con->cb.len,<br />
					  PAGE_CACHE_SIZE);<br />
	if (ret == -EBADMSG) {<br />
		log_print(&raquo;lowcomms: addr=%p, base=%u, len=%u, &raquo;<br />
			  &laquo;iov_len=%u, iov_base[0]=%p, read=%d&raquo;,<br />
			  page_address(con->rx_page), con->cb.base, con->cb.len,<br />
			  len, iov[0].iov_base, r);<br />
	}<br />
	if (ret < 0)<br />
		goto out_close;<br />
	cbuf_eat(&#038;con->cb, ret);</p>
<p>	if (cbuf_empty(&#038;con->cb) &#038;&#038; !call_again_soon) {<br />
		__free_page(con->rx_page);<br />
		con->rx_page = NULL;<br />
	}</p>
<p>	if (call_again_soon)<br />
		goto out_resched;<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	return 0;</p>
<p>out_resched:<br />
	if (!test_and_set_bit(CF_READ_PENDING, &#038;con->flags))<br />
		queue_work(recv_workqueue, &#038;con->rwork);<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	return -EAGAIN;</p>
<p>out_close:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	if (ret != -EAGAIN) {<br />
		close_connection(con, false);<br />
		/* Reconnect when there is something to send */<br />
	}<br />
	/* Don&#8217;t return success if we really got EOF */<br />
	if (ret == 0)<br />
		ret = -EAGAIN;</p>
<p>	return ret;<br />
}</p>
<p>/* Listening socket is busy, accept a connection */<br />
static int tcp_accept_from_sock(struct connection *con)<br />
{<br />
	int result;<br />
	struct sockaddr_storage peeraddr;<br />
	struct socket *newsock;<br />
	int len;<br />
	int nodeid;<br />
	struct connection *newcon;<br />
	struct connection *addcon;</p>
<p>	memset(&#038;peeraddr, 0, sizeof(peeraddr));<br />
	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,<br />
				  IPPROTO_TCP, &#038;newsock);<br />
	if (result < 0)<br />
		return -ENOMEM;</p>
<p>	mutex_lock_nested(&#038;con->sock_mutex, 0);</p>
<p>	result = -ENOTCONN;<br />
	if (con->sock == NULL)<br />
		goto accept_err;</p>
<p>	newsock->type = con->sock->type;<br />
	newsock->ops = con->sock->ops;</p>
<p>	result = con->sock->ops->accept(con->sock, newsock, O_NONBLOCK);<br />
	if (result < 0)<br />
		goto accept_err;</p>
<p>	/* Get the connected socket's peer */<br />
	memset(&#038;peeraddr, 0, sizeof(peeraddr));<br />
	if (newsock->ops->getname(newsock, (struct sockaddr *)&#038;peeraddr,<br />
				  &#038;len, 2)) {<br />
		result = -ECONNABORTED;<br />
		goto accept_err;<br />
	}</p>
<p>	/* Get the new node&#8217;s NODEID */<br />
	make_sockaddr(&#038;peeraddr, 0, &#038;len);<br />
	if (dlm_addr_to_nodeid(&#038;peeraddr, &#038;nodeid)) {<br />
		log_print(&raquo;connect from non cluster node&raquo;);<br />
		sock_release(newsock);<br />
		mutex_unlock(&#038;con->sock_mutex);<br />
		return -1;<br />
	}</p>
<p>	log_print(&raquo;got connection from %d&raquo;, nodeid);</p>
<p>	/*  Check to see if we already have a connection to this node. This<br />
	 *  could happen if the two nodes initiate a connection at roughly<br />
	 *  the same time and the connections cross on the wire.<br />
	 *  In this case we store the incoming one in &laquo;othercon&raquo;<br />
	 */<br />
	newcon = nodeid2con(nodeid, GFP_NOFS);<br />
	if (!newcon) {<br />
		result = -ENOMEM;<br />
		goto accept_err;<br />
	}<br />
	mutex_lock_nested(&#038;newcon->sock_mutex, 1);<br />
	if (newcon->sock) {<br />
		struct connection *othercon = newcon->othercon;</p>
<p>		if (!othercon) {<br />
			othercon = kmem_cache_zalloc(con_cache, GFP_NOFS);<br />
			if (!othercon) {<br />
				log_print(&raquo;failed to allocate incoming socket&raquo;);<br />
				mutex_unlock(&#038;newcon->sock_mutex);<br />
				result = -ENOMEM;<br />
				goto accept_err;<br />
			}<br />
			othercon->nodeid = nodeid;<br />
			othercon->rx_action = receive_from_sock;<br />
			mutex_init(&#038;othercon->sock_mutex);<br />
			INIT_WORK(&#038;othercon->swork, process_send_sockets);<br />
			INIT_WORK(&#038;othercon->rwork, process_recv_sockets);<br />
			set_bit(CF_IS_OTHERCON, &#038;othercon->flags);<br />
		}<br />
		if (!othercon->sock) {<br />
			newcon->othercon = othercon;<br />
			othercon->sock = newsock;<br />
			newsock->sk->sk_user_data = othercon;<br />
			add_sock(newsock, othercon);<br />
			addcon = othercon;<br />
		}<br />
		else {<br />
			printk(&raquo;Extra connection from node %d attempted\n&raquo;, nodeid);<br />
			result = -EAGAIN;<br />
			mutex_unlock(&#038;newcon->sock_mutex);<br />
			goto accept_err;<br />
		}<br />
	}<br />
	else {<br />
		newsock->sk->sk_user_data = newcon;<br />
		newcon->rx_action = receive_from_sock;<br />
		add_sock(newsock, newcon);<br />
		addcon = newcon;<br />
	}</p>
<p>	mutex_unlock(&#038;newcon->sock_mutex);</p>
<p>	/*<br />
	 * Add it to the active queue in case we got data<br />
	 * beween processing the accept adding the socket<br />
	 * to the read_sockets list<br />
	 */<br />
	if (!test_and_set_bit(CF_READ_PENDING, &#038;addcon->flags))<br />
		queue_work(recv_workqueue, &#038;addcon->rwork);<br />
	mutex_unlock(&#038;con->sock_mutex);</p>
<p>	return 0;</p>
<p>accept_err:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	sock_release(newsock);</p>
<p>	if (result != -EAGAIN)<br />
		log_print(&raquo;error accepting connection from node: %d&raquo;, result);<br />
	return result;<br />
}</p>
<p>static void free_entry(struct writequeue_entry *e)<br />
{<br />
	__free_page(e->page);<br />
	kfree(e);<br />
}</p>
<p>/* Initiate an SCTP association.<br />
   This is a special case of send_to_sock() in that we don&#8217;t yet have a<br />
   peeled-off socket for this association, so we use the listening socket<br />
   and add the primary IP address of the remote node.<br />
 */<br />
static void sctp_init_assoc(struct connection *con)<br />
{<br />
	struct sockaddr_storage rem_addr;<br />
	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];<br />
	struct msghdr outmessage;<br />
	struct cmsghdr *cmsg;<br />
	struct sctp_sndrcvinfo *sinfo;<br />
	struct connection *base_con;<br />
	struct writequeue_entry *e;<br />
	int len, offset;<br />
	int ret;<br />
	int addrlen;<br />
	struct kvec iov[1];</p>
<p>	if (test_and_set_bit(CF_INIT_PENDING, &#038;con->flags))<br />
		return;</p>
<p>	if (con->retries++ > MAX_CONNECT_RETRIES)<br />
		return;</p>
<p>	if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&#038;rem_addr)) {<br />
		log_print(&raquo;no address for nodeid %d&raquo;, con->nodeid);<br />
		return;<br />
	}<br />
	base_con = nodeid2con(0, 0);<br />
	BUG_ON(base_con == NULL);</p>
<p>	make_sockaddr(&#038;rem_addr, dlm_config.ci_tcp_port, &#038;addrlen);</p>
<p>	outmessage.msg_name = &#038;rem_addr;<br />
	outmessage.msg_namelen = addrlen;<br />
	outmessage.msg_control = outcmsg;<br />
	outmessage.msg_controllen = sizeof(outcmsg);<br />
	outmessage.msg_flags = MSG_EOR;</p>
<p>	spin_lock(&#038;con->writequeue_lock);</p>
<p>	if (list_empty(&#038;con->writequeue)) {<br />
		spin_unlock(&#038;con->writequeue_lock);<br />
		log_print(&raquo;writequeue empty for nodeid %d&raquo;, con->nodeid);<br />
		return;<br />
	}</p>
<p>	e = list_first_entry(&#038;con->writequeue, struct writequeue_entry, list);<br />
	len = e->len;<br />
	offset = e->offset;<br />
	spin_unlock(&#038;con->writequeue_lock);</p>
<p>	/* Send the first block off the write queue */<br />
	iov[0].iov_base = page_address(e->page)+offset;<br />
	iov[0].iov_len = len;</p>
<p>	cmsg = CMSG_FIRSTHDR(&#038;outmessage);<br />
	cmsg->cmsg_level = IPPROTO_SCTP;<br />
	cmsg->cmsg_type = SCTP_SNDRCV;<br />
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));<br />
	sinfo = CMSG_DATA(cmsg);<br />
	memset(sinfo, 0&#215;00, sizeof(struct sctp_sndrcvinfo));<br />
	sinfo->sinfo_ppid = cpu_to_le32(dlm_our_nodeid());<br />
	outmessage.msg_controllen = cmsg->cmsg_len;</p>
<p>	ret = kernel_sendmsg(base_con->sock, &#038;outmessage, iov, 1, len);<br />
	if (ret < 0) {<br />
		log_print("Send first packet to node %d failed: %d",<br />
			  con->nodeid, ret);</p>
<p>		/* Try again later */<br />
		clear_bit(CF_CONNECT_PENDING, &#038;con->flags);<br />
		clear_bit(CF_INIT_PENDING, &#038;con->flags);<br />
	}<br />
	else {<br />
		spin_lock(&#038;con->writequeue_lock);<br />
		e->offset += ret;<br />
		e->len -= ret;</p>
<p>		if (e->len == 0 &#038;&#038; e->users == 0) {<br />
			list_del(&#038;e->list);<br />
			free_entry(e);<br />
		}<br />
		spin_unlock(&#038;con->writequeue_lock);<br />
	}<br />
}</p>
<p>/* Connect a new socket to its peer */<br />
static void tcp_connect_to_sock(struct connection *con)<br />
{<br />
	int result = -EHOSTUNREACH;<br />
	struct sockaddr_storage saddr, src_addr;<br />
	int addr_len;<br />
	struct socket *sock = NULL;</p>
<p>	if (con->nodeid == 0) {<br />
		log_print(&raquo;attempt to connect sock 0 foiled&raquo;);<br />
		return;<br />
	}</p>
<p>	mutex_lock(&#038;con->sock_mutex);<br />
	if (con->retries++ > MAX_CONNECT_RETRIES)<br />
		goto out;</p>
<p>	/* Some odd races can cause double-connects, ignore them */<br />
	if (con->sock) {<br />
		result = 0;<br />
		goto out;<br />
	}</p>
<p>	/* Create a socket to communicate with */<br />
	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,<br />
				  IPPROTO_TCP, &#038;sock);<br />
	if (result < 0)<br />
		goto out_err;</p>
<p>	memset(&#038;saddr, 0, sizeof(saddr));<br />
	if (dlm_nodeid_to_addr(con->nodeid, &#038;saddr))<br />
		goto out_err;</p>
<p>	sock->sk->sk_user_data = con;<br />
	con->rx_action = receive_from_sock;<br />
	con->connect_action = tcp_connect_to_sock;<br />
	add_sock(sock, con);</p>
<p>	/* Bind to our cluster-known address connecting to avoid<br />
	   routing problems */<br />
	memcpy(&#038;src_addr, dlm_local_addr[0], sizeof(src_addr));<br />
	make_sockaddr(&#038;src_addr, 0, &#038;addr_len);<br />
	result = sock->ops->bind(sock, (struct sockaddr *) &#038;src_addr,<br />
				 addr_len);<br />
	if (result < 0) {<br />
		log_print("could not bind for connect: %d", result);<br />
		/* This *may* not indicate a critical error */<br />
	}</p>
<p>	make_sockaddr(&#038;saddr, dlm_config.ci_tcp_port, &#038;addr_len);</p>
<p>	log_print("connecting to %d", con->nodeid);<br />
	result =<br />
		sock->ops->connect(sock, (struct sockaddr *)&#038;saddr, addr_len,<br />
				   O_NONBLOCK);<br />
	if (result == -EINPROGRESS)<br />
		result = 0;<br />
	if (result == 0)<br />
		goto out;</p>
<p>out_err:<br />
	if (con->sock) {<br />
		sock_release(con->sock);<br />
		con->sock = NULL;<br />
	} else if (sock) {<br />
		sock_release(sock);<br />
	}<br />
	/*<br />
	 * Some errors are fatal and this list might need adjusting. For other<br />
	 * errors we try again until the max number of retries is reached.<br />
	 */<br />
	if (result != -EHOSTUNREACH &#038;&#038; result != -ENETUNREACH &#038;&#038;<br />
	    result != -ENETDOWN &#038;&#038; result != -EINVAL<br />
	    &#038;&#038; result != -EPROTONOSUPPORT) {<br />
		lowcomms_connect_sock(con);<br />
		result = 0;<br />
	}<br />
out:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	return;<br />
}</p>
<p>static struct socket *tcp_create_listen_sock(struct connection *con,<br />
					     struct sockaddr_storage *saddr)<br />
{<br />
	struct socket *sock = NULL;<br />
	int result = 0;<br />
	int one = 1;<br />
	int addr_len;</p>
<p>	if (dlm_local_addr[0]->ss_family == AF_INET)<br />
		addr_len = sizeof(struct sockaddr_in);<br />
	else<br />
		addr_len = sizeof(struct sockaddr_in6);</p>
<p>	/* Create a socket to communicate with */<br />
	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,<br />
				  IPPROTO_TCP, &#038;sock);<br />
	if (result < 0) {<br />
		log_print("Can't create listening comms socket");<br />
		goto create_out;<br />
	}</p>
<p>	result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,<br />
				   (char *)&#038;one, sizeof(one));</p>
<p>	if (result < 0) {<br />
		log_print("Failed to set SO_REUSEADDR on socket: %d", result);<br />
	}<br />
	sock->sk->sk_user_data = con;<br />
	con->rx_action = tcp_accept_from_sock;<br />
	con->connect_action = tcp_connect_to_sock;<br />
	con->sock = sock;</p>
<p>	/* Bind to our port */<br />
	make_sockaddr(saddr, dlm_config.ci_tcp_port, &#038;addr_len);<br />
	result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);<br />
	if (result < 0) {<br />
		log_print("Can't bind to port %d", dlm_config.ci_tcp_port);<br />
		sock_release(sock);<br />
		sock = NULL;<br />
		con->sock = NULL;<br />
		goto create_out;<br />
	}<br />
	result = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,<br />
				 (char *)&#038;one, sizeof(one));<br />
	if (result < 0) {<br />
		log_print("Set keepalive failed: %d", result);<br />
	}</p>
<p>	result = sock->ops->listen(sock, 5);<br />
	if (result < 0) {<br />
		log_print("Can't listen on port %d", dlm_config.ci_tcp_port);<br />
		sock_release(sock);<br />
		sock = NULL;<br />
		goto create_out;<br />
	}</p>
<p>create_out:<br />
	return sock;<br />
}</p>
<p>/* Get local addresses */<br />
static void init_local(void)<br />
{<br />
	struct sockaddr_storage sas, *addr;<br />
	int i;</p>
<p>	dlm_local_count = 0;<br />
	for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {<br />
		if (dlm_our_addr(&#038;sas, i))<br />
			break;</p>
<p>		addr = kmalloc(sizeof(*addr), GFP_KERNEL);<br />
		if (!addr)<br />
			break;<br />
		memcpy(addr, &#038;sas, sizeof(*addr));<br />
		dlm_local_addr[dlm_local_count++] = addr;<br />
	}<br />
}</p>
<p>/* Bind to an IP address. SCTP allows multiple address so it can do<br />
   multi-homing */<br />
static int add_sctp_bind_addr(struct connection *sctp_con,<br />
			      struct sockaddr_storage *addr,<br />
			      int addr_len, int num)<br />
{<br />
	int result = 0;</p>
<p>	if (num == 1)<br />
		result = kernel_bind(sctp_con->sock,<br />
				     (struct sockaddr *) addr,<br />
				     addr_len);<br />
	else<br />
		result = kernel_setsockopt(sctp_con->sock, SOL_SCTP,<br />
					   SCTP_SOCKOPT_BINDX_ADD,<br />
					   (char *)addr, addr_len);</p>
<p>	if (result < 0)<br />
		log_print("Can't bind to port %d addr number %d",<br />
			  dlm_config.ci_tcp_port, num);</p>
<p>	return result;<br />
}</p>
<p>/* Initialise SCTP socket and bind to all interfaces */<br />
static int sctp_listen_for_all(void)<br />
{<br />
	struct socket *sock = NULL;<br />
	struct sockaddr_storage localaddr;<br />
	struct sctp_event_subscribe subscribe;<br />
	int result = -EINVAL, num = 1, i, addr_len;<br />
	struct connection *con = nodeid2con(0, GFP_KERNEL);<br />
	int bufsize = NEEDED_RMEM;</p>
<p>	if (!con)<br />
		return -ENOMEM;</p>
<p>	log_print("Using SCTP for communications");</p>
<p>	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,<br />
				  IPPROTO_SCTP, &#038;sock);<br />
	if (result < 0) {<br />
		log_print("Can't create comms socket, check SCTP is loaded");<br />
		goto out;<br />
	}</p>
<p>	/* Listen for events */<br />
	memset(&#038;subscribe, 0, sizeof(subscribe));<br />
	subscribe.sctp_data_io_event = 1;<br />
	subscribe.sctp_association_event = 1;<br />
	subscribe.sctp_send_failure_event = 1;<br />
	subscribe.sctp_shutdown_event = 1;<br />
	subscribe.sctp_partial_delivery_event = 1;</p>
<p>	result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE,<br />
				 (char *)&#038;bufsize, sizeof(bufsize));<br />
	if (result)<br />
		log_print("Error increasing buffer space on socket %d", result);</p>
<p>	result = kernel_setsockopt(sock, SOL_SCTP, SCTP_EVENTS,<br />
				   (char *)&#038;subscribe, sizeof(subscribe));<br />
	if (result < 0) {<br />
		log_print("Failed to set SCTP_EVENTS on socket: result=%d",<br />
			  result);<br />
		goto create_delsock;<br />
	}</p>
<p>	/* Init con struct */<br />
	sock->sk->sk_user_data = con;<br />
	con->sock = sock;<br />
	con->sock->sk->sk_data_ready = lowcomms_data_ready;<br />
	con->rx_action = receive_from_sock;<br />
	con->connect_action = sctp_init_assoc;</p>
<p>	/* Bind to all interfaces. */<br />
	for (i = 0; i < dlm_local_count; i++) {<br />
		memcpy(&#038;localaddr, dlm_local_addr[i], sizeof(localaddr));<br />
		make_sockaddr(&#038;localaddr, dlm_config.ci_tcp_port, &#038;addr_len);</p>
<p>		result = add_sctp_bind_addr(con, &#038;localaddr, addr_len, num);<br />
		if (result)<br />
			goto create_delsock;<br />
		++num;<br />
	}</p>
<p>	result = sock->ops->listen(sock, 5);<br />
	if (result < 0) {<br />
		log_print("Can't set socket listening");<br />
		goto create_delsock;<br />
	}</p>
<p>	return 0;</p>
<p>create_delsock:<br />
	sock_release(sock);<br />
	con->sock = NULL;<br />
out:<br />
	return result;<br />
}</p>
<p>static int tcp_listen_for_all(void)<br />
{<br />
	struct socket *sock = NULL;<br />
	struct connection *con = nodeid2con(0, GFP_KERNEL);<br />
	int result = -EINVAL;</p>
<p>	if (!con)<br />
		return -ENOMEM;</p>
<p>	/* We don&#8217;t support multi-homed hosts */<br />
	if (dlm_local_addr[1] != NULL) {<br />
		log_print(&raquo;TCP protocol can&#8217;t handle multi-homed hosts, &raquo;<br />
			  &laquo;try SCTP&raquo;);<br />
		return -EINVAL;<br />
	}</p>
<p>	log_print(&raquo;Using TCP for communications&raquo;);</p>
<p>	sock = tcp_create_listen_sock(con, dlm_local_addr[0]);<br />
	if (sock) {<br />
		add_sock(sock, con);<br />
		result = 0;<br />
	}<br />
	else {<br />
		result = -EADDRINUSE;<br />
	}</p>
<p>	return result;<br />
}</p>
<p>static struct writequeue_entry *new_writequeue_entry(struct connection *con,<br />
						     gfp_t allocation)<br />
{<br />
	struct writequeue_entry *entry;</p>
<p>	entry = kmalloc(sizeof(struct writequeue_entry), allocation);<br />
	if (!entry)<br />
		return NULL;</p>
<p>	entry->page = alloc_page(allocation);<br />
	if (!entry->page) {<br />
		kfree(entry);<br />
		return NULL;<br />
	}</p>
<p>	entry->offset = 0;<br />
	entry->len = 0;<br />
	entry->end = 0;<br />
	entry->users = 0;<br />
	entry->con = con;</p>
<p>	return entry;<br />
}</p>
<p>void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)<br />
{<br />
	struct connection *con;<br />
	struct writequeue_entry *e;<br />
	int offset = 0;<br />
	int users = 0;</p>
<p>	con = nodeid2con(nodeid, allocation);<br />
	if (!con)<br />
		return NULL;</p>
<p>	spin_lock(&#038;con->writequeue_lock);<br />
	e = list_entry(con->writequeue.prev, struct writequeue_entry, list);<br />
	if ((&#038;e->list == &#038;con->writequeue) ||<br />
	    (PAGE_CACHE_SIZE &#8211; e->end < len)) {<br />
		e = NULL;<br />
	} else {<br />
		offset = e->end;<br />
		e->end += len;<br />
		users = e->users++;<br />
	}<br />
	spin_unlock(&#038;con->writequeue_lock);</p>
<p>	if (e) {<br />
	got_one:<br />
		*ppc = page_address(e->page) + offset;<br />
		return e;<br />
	}</p>
<p>	e = new_writequeue_entry(con, allocation);<br />
	if (e) {<br />
		spin_lock(&#038;con->writequeue_lock);<br />
		offset = e->end;<br />
		e->end += len;<br />
		users = e->users++;<br />
		list_add_tail(&#038;e->list, &#038;con->writequeue);<br />
		spin_unlock(&#038;con->writequeue_lock);<br />
		goto got_one;<br />
	}<br />
	return NULL;<br />
}</p>
<p>void dlm_lowcomms_commit_buffer(void *mh)<br />
{<br />
	struct writequeue_entry *e = (struct writequeue_entry *)mh;<br />
	struct connection *con = e->con;<br />
	int users;</p>
<p>	spin_lock(&#038;con->writequeue_lock);<br />
	users = &#8211;e->users;<br />
	if (users)<br />
		goto out;<br />
	e->len = e->end &#8211; e->offset;<br />
	spin_unlock(&#038;con->writequeue_lock);</p>
<p>	if (!test_and_set_bit(CF_WRITE_PENDING, &#038;con->flags)) {<br />
		queue_work(send_workqueue, &#038;con->swork);<br />
	}<br />
	return;</p>
<p>out:<br />
	spin_unlock(&#038;con->writequeue_lock);<br />
	return;<br />
}</p>
<p>/* Send a message */<br />
static void send_to_sock(struct connection *con)<br />
{<br />
	int ret = 0;<br />
	const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;<br />
	struct writequeue_entry *e;<br />
	int len, offset;</p>
<p>	mutex_lock(&#038;con->sock_mutex);<br />
	if (con->sock == NULL)<br />
		goto out_connect;</p>
<p>	spin_lock(&#038;con->writequeue_lock);<br />
	for (;;) {<br />
		e = list_entry(con->writequeue.next, struct writequeue_entry,<br />
			       list);<br />
		if ((struct list_head *) e == &#038;con->writequeue)<br />
			break;</p>
<p>		len = e->len;<br />
		offset = e->offset;<br />
		BUG_ON(len == 0 &#038;&#038; e->users == 0);<br />
		spin_unlock(&#038;con->writequeue_lock);</p>
<p>		ret = 0;<br />
		if (len) {<br />
			ret = kernel_sendpage(con->sock, e->page, offset, len,<br />
					      msg_flags);<br />
			if (ret == -EAGAIN || ret == 0) {<br />
				cond_resched();<br />
				goto out;<br />
			}<br />
			if (ret <= 0)<br />
				goto send_error;<br />
		}<br />
			/* Don't starve people filling buffers */<br />
			cond_resched();</p>
<p>		spin_lock(&#038;con->writequeue_lock);<br />
		e->offset += ret;<br />
		e->len -= ret;</p>
<p>		if (e->len == 0 &#038;&#038; e->users == 0) {<br />
			list_del(&#038;e->list);<br />
			free_entry(e);<br />
			continue;<br />
		}<br />
	}<br />
	spin_unlock(&#038;con->writequeue_lock);<br />
out:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	return;</p>
<p>send_error:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	close_connection(con, false);<br />
	lowcomms_connect_sock(con);<br />
	return;</p>
<p>out_connect:<br />
	mutex_unlock(&#038;con->sock_mutex);<br />
	if (!test_bit(CF_INIT_PENDING, &#038;con->flags))<br />
		lowcomms_connect_sock(con);<br />
	return;<br />
}</p>
<p>static void clean_one_writequeue(struct connection *con)<br />
{<br />
	struct writequeue_entry *e, *safe;</p>
<p>	spin_lock(&#038;con->writequeue_lock);<br />
	list_for_each_entry_safe(e, safe, &#038;con->writequeue, list) {<br />
		list_del(&#038;e->list);<br />
		free_entry(e);<br />
	}<br />
	spin_unlock(&#038;con->writequeue_lock);<br />
}</p>
<p>/* Called from recovery when it knows that a node has<br />
   left the cluster */<br />
int dlm_lowcomms_close(int nodeid)<br />
{<br />
	struct connection *con;</p>
<p>	log_print(&raquo;closing connection to node %d&raquo;, nodeid);<br />
	con = nodeid2con(nodeid, 0);<br />
	if (con) {<br />
		clear_bit(CF_CONNECT_PENDING, &#038;con->flags);<br />
		clear_bit(CF_WRITE_PENDING, &#038;con->flags);<br />
		set_bit(CF_CLOSE, &#038;con->flags);<br />
		if (cancel_work_sync(&#038;con->swork))<br />
			log_print(&raquo;canceled swork for node %d&raquo;, nodeid);<br />
		if (cancel_work_sync(&#038;con->rwork))<br />
			log_print(&raquo;canceled rwork for node %d&raquo;, nodeid);<br />
		clean_one_writequeue(con);<br />
		close_connection(con, true);<br />
	}<br />
	return 0;<br />
}</p>
<p>/* Receive workqueue function */<br />
static void process_recv_sockets(struct work_struct *work)<br />
{<br />
	struct connection *con = container_of(work, struct connection, rwork);<br />
	int err;</p>
<p>	clear_bit(CF_READ_PENDING, &#038;con->flags);<br />
	do {<br />
		err = con->rx_action(con);<br />
	} while (!err);<br />
}</p>
<p>/* Send workqueue function */<br />
static void process_send_sockets(struct work_struct *work)<br />
{<br />
	struct connection *con = container_of(work, struct connection, swork);</p>
<p>	if (test_and_clear_bit(CF_CONNECT_PENDING, &#038;con->flags)) {<br />
		con->connect_action(con);<br />
		set_bit(CF_WRITE_PENDING, &#038;con->flags);<br />
	}<br />
	if (test_and_clear_bit(CF_WRITE_PENDING, &#038;con->flags))<br />
		send_to_sock(con);<br />
}</p>
<p>/* Discard all entries on the write queues */<br />
static void clean_writequeues(void)<br />
{<br />
	foreach_conn(clean_one_writequeue);<br />
}</p>
<p>static void work_stop(void)<br />
{<br />
	destroy_workqueue(recv_workqueue);<br />
	destroy_workqueue(send_workqueue);<br />
}</p>
<p>static int work_start(void)<br />
{<br />
	int error;<br />
	recv_workqueue = create_workqueue(&raquo;dlm_recv&raquo;);<br />
	error = IS_ERR(recv_workqueue);<br />
	if (error) {<br />
		log_print(&raquo;can&#8217;t start dlm_recv %d&raquo;, error);<br />
		return error;<br />
	}</p>
<p>	send_workqueue = create_singlethread_workqueue(&raquo;dlm_send&raquo;);<br />
	error = IS_ERR(send_workqueue);<br />
	if (error) {<br />
		log_print(&raquo;can&#8217;t start dlm_send %d&raquo;, error);<br />
		destroy_workqueue(recv_workqueue);<br />
		return error;<br />
	}</p>
<p>	return 0;<br />
}</p>
<p>static void stop_conn(struct connection *con)<br />
{<br />
	con->flags |= 0&#215;0F;<br />
	if (con->sock &#038;&#038; con->sock->sk)<br />
		con->sock->sk->sk_user_data = NULL;<br />
}</p>
<p>static void free_conn(struct connection *con)<br />
{<br />
	close_connection(con, true);<br />
	if (con->othercon)<br />
		kmem_cache_free(con_cache, con->othercon);<br />
	hlist_del(&#038;con->list);<br />
	kmem_cache_free(con_cache, con);<br />
}</p>
<p>void dlm_lowcomms_stop(void)<br />
{<br />
	/* Set all the flags to prevent any<br />
	   socket activity.<br />
	*/<br />
	mutex_lock(&#038;connections_lock);<br />
	foreach_conn(stop_conn);<br />
	mutex_unlock(&#038;connections_lock);</p>
<p>	work_stop();</p>
<p>	mutex_lock(&#038;connections_lock);<br />
	clean_writequeues();</p>
<p>	foreach_conn(free_conn);</p>
<p>	mutex_unlock(&#038;connections_lock);<br />
	kmem_cache_destroy(con_cache);<br />
}</p>
<p>int dlm_lowcomms_start(void)<br />
{<br />
	int error = -EINVAL;<br />
	struct connection *con;<br />
	int i;</p>
<p>	for (i = 0; i < CONN_HASH_SIZE; i++)<br />
		INIT_HLIST_HEAD(&#038;connection_hash[i]);</p>
<p>	init_local();<br />
	if (!dlm_local_count) {<br />
		error = -ENOTCONN;<br />
		log_print(&raquo;no local IP address has been set&raquo;);<br />
		goto out;<br />
	}</p>
<p>	error = -ENOMEM;<br />
	con_cache = kmem_cache_create(&raquo;dlm_conn&raquo;, sizeof(struct connection),<br />
				      __alignof__(struct connection), 0,<br />
				      NULL);<br />
	if (!con_cache)<br />
		goto out;</p>
<p>	/* Start listening */<br />
	if (dlm_config.ci_protocol == 0)<br />
		error = tcp_listen_for_all();<br />
	else<br />
		error = sctp_listen_for_all();<br />
	if (error)<br />
		goto fail_unlisten;</p>
<p>	error = work_start();<br />
	if (error)<br />
		goto fail_unlisten;</p>
<p>	return 0;</p>
<p>fail_unlisten:<br />
	con = nodeid2con(0,0);<br />
	if (con) {<br />
		close_connection(con, false);<br />
		kmem_cache_free(con_cache, con);<br />
	}<br />
	kmem_cache_destroy(con_cache);</p>
<p>out:<br />
	return error;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lowcomms-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lockspace.h</title>
		<link>http://lynyrd.ru/lockspace-h</link>
		<comments>http://lynyrd.ru/lockspace-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:50:59 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/lockspace-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1037"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __LOCKSPACE_DOT_H__<br />
#define __LOCKSPACE_DOT_H__</p>
<p>int dlm_lockspace_init(void);<br />
void dlm_lockspace_exit(void);<br />
struct dlm_ls *dlm_find_lockspace_global(uint32_t id);<br />
struct dlm_ls *dlm_find_lockspace_local(void *id);<br />
struct dlm_ls *dlm_find_lockspace_device(int minor);<br />
void dlm_put_lockspace(struct dlm_ls *ls);<br />
void dlm_stop_lockspaces(void);</p>
<p>#endif				/* __LOCKSPACE_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lockspace-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lockspace.c</title>
		<link>http://lynyrd.ru/lockspace-c</link>
		<comments>http://lynyrd.ru/lockspace-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:50:40 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1035</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2008 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1035"></span><br />
**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;recoverd.h&raquo;<br />
#include &laquo;ast.h&raquo;<br />
#include &laquo;dir.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;memory.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;recover.h&raquo;<br />
#include &laquo;requestqueue.h&raquo;<br />
#include &laquo;user.h&raquo;</p>
<p>static int			ls_count;<br />
static struct mutex		ls_lock;<br />
static struct list_head		lslist;<br />
static spinlock_t		lslist_lock;<br />
static struct task_struct *	scand_task;</p>
<p>static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)<br />
{<br />
	ssize_t ret = len;<br />
	int n = simple_strtol(buf, NULL, 0);</p>
<p>	ls = dlm_find_lockspace_local(ls->ls_local_handle);<br />
	if (!ls)<br />
		return -EINVAL;</p>
<p>	switch (n) {<br />
	case 0:<br />
		dlm_ls_stop(ls);<br />
		break;<br />
	case 1:<br />
		dlm_ls_start(ls);<br />
		break;<br />
	default:<br />
		ret = -EINVAL;<br />
	}<br />
	dlm_put_lockspace(ls);<br />
	return ret;<br />
}</p>
<p>static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)<br />
{<br />
	ls->ls_uevent_result = simple_strtol(buf, NULL, 0);<br />
	set_bit(LSFL_UEVENT_WAIT, &#038;ls->ls_flags);<br />
	wake_up(&#038;ls->ls_uevent_wait);<br />
	return len;<br />
}</p>
<p>static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)<br />
{<br />
	return snprintf(buf, PAGE_SIZE, &laquo;%u\n&raquo;, ls->ls_global_id);<br />
}</p>
<p>static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)<br />
{<br />
	ls->ls_global_id = simple_strtoul(buf, NULL, 0);<br />
	return len;<br />
}</p>
<p>static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)<br />
{<br />
	uint32_t status = dlm_recover_status(ls);<br />
	return snprintf(buf, PAGE_SIZE, &laquo;%x\n&raquo;, status);<br />
}</p>
<p>static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf)<br />
{<br />
	return snprintf(buf, PAGE_SIZE, &laquo;%d\n&raquo;, ls->ls_recover_nodeid);<br />
}</p>
<p>struct dlm_attr {<br />
	struct attribute attr;<br />
	ssize_t (*show)(struct dlm_ls *, char *);<br />
	ssize_t (*store)(struct dlm_ls *, const char *, size_t);<br />
};</p>
<p>static struct dlm_attr dlm_attr_control = {<br />
	.attr  = {.name = &laquo;control&raquo;, .mode = S_IWUSR},<br />
	.store = dlm_control_store<br />
};</p>
<p>static struct dlm_attr dlm_attr_event = {<br />
	.attr  = {.name = &laquo;event_done&raquo;, .mode = S_IWUSR},<br />
	.store = dlm_event_store<br />
};</p>
<p>static struct dlm_attr dlm_attr_id = {<br />
	.attr  = {.name = &laquo;id&raquo;, .mode = S_IRUGO | S_IWUSR},<br />
	.show  = dlm_id_show,<br />
	.store = dlm_id_store<br />
};</p>
<p>static struct dlm_attr dlm_attr_recover_status = {<br />
	.attr  = {.name = &laquo;recover_status&raquo;, .mode = S_IRUGO},<br />
	.show  = dlm_recover_status_show<br />
};</p>
<p>static struct dlm_attr dlm_attr_recover_nodeid = {<br />
	.attr  = {.name = &laquo;recover_nodeid&raquo;, .mode = S_IRUGO},<br />
	.show  = dlm_recover_nodeid_show<br />
};</p>
<p>static struct attribute *dlm_attrs[] = {<br />
	&#038;dlm_attr_control.attr,<br />
	&#038;dlm_attr_event.attr,<br />
	&#038;dlm_attr_id.attr,<br />
	&#038;dlm_attr_recover_status.attr,<br />
	&#038;dlm_attr_recover_nodeid.attr,<br />
	NULL,<br />
};</p>
<p>static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,<br />
			     char *buf)<br />
{<br />
	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);<br />
	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);<br />
	return a->show ? a->show(ls, buf) : 0;<br />
}</p>
<p>static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,<br />
			      const char *buf, size_t len)<br />
{<br />
	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);<br />
	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);<br />
	return a->store ? a->store(ls, buf, len) : len;<br />
}</p>
<p>static void lockspace_kobj_release(struct kobject *k)<br />
{<br />
	struct dlm_ls *ls  = container_of(k, struct dlm_ls, ls_kobj);<br />
	kfree(ls);<br />
}</p>
<p>static struct sysfs_ops dlm_attr_ops = {<br />
	.show  = dlm_attr_show,<br />
	.store = dlm_attr_store,<br />
};</p>
<p>static struct kobj_type dlm_ktype = {<br />
	.default_attrs = dlm_attrs,<br />
	.sysfs_ops     = &#038;dlm_attr_ops,<br />
	.release       = lockspace_kobj_release,<br />
};</p>
<p>static struct kset *dlm_kset;</p>
<p>static int do_uevent(struct dlm_ls *ls, int in)<br />
{<br />
	int error;</p>
<p>	if (in)<br />
		kobject_uevent(&#038;ls->ls_kobj, KOBJ_ONLINE);<br />
	else<br />
		kobject_uevent(&#038;ls->ls_kobj, KOBJ_OFFLINE);</p>
<p>	log_debug(ls, &laquo;%s the lockspace group&#8230;&raquo;, in ? &laquo;joining&raquo; : &laquo;leaving&raquo;);</p>
<p>	/* dlm_controld will see the uevent, do the necessary group management<br />
	   and then write to sysfs to wake us */</p>
<p>	error = wait_event_interruptible(ls->ls_uevent_wait,<br />
			test_and_clear_bit(LSFL_UEVENT_WAIT, &#038;ls->ls_flags));</p>
<p>	log_debug(ls, &laquo;group event done %d %d&raquo;, error, ls->ls_uevent_result);</p>
<p>	if (error)<br />
		goto out;</p>
<p>	error = ls->ls_uevent_result;<br />
 out:<br />
	if (error)<br />
		log_error(ls, &laquo;group %s failed %d %d&raquo;, in ? &laquo;join&raquo; : &laquo;leave&raquo;,<br />
			  error, ls->ls_uevent_result);<br />
	return error;<br />
}</p>
<p>int __init dlm_lockspace_init(void)<br />
{<br />
	ls_count = 0;<br />
	mutex_init(&#038;ls_lock);<br />
	INIT_LIST_HEAD(&#038;lslist);<br />
	spin_lock_init(&#038;lslist_lock);</p>
<p>	dlm_kset = kset_create_and_add(&raquo;dlm&raquo;, NULL, kernel_kobj);<br />
	if (!dlm_kset) {<br />
		printk(KERN_WARNING &laquo;%s: can not create kset\n&raquo;, __func__);<br />
		return -ENOMEM;<br />
	}<br />
	return 0;<br />
}</p>
<p>void dlm_lockspace_exit(void)<br />
{<br />
	kset_unregister(dlm_kset);<br />
}</p>
<p>static struct dlm_ls *find_ls_to_scan(void)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		if (time_after_eq(jiffies, ls->ls_scan_time +<br />
					    dlm_config.ci_scan_secs * HZ)) {<br />
			spin_unlock(&#038;lslist_lock);<br />
			return ls;<br />
		}<br />
	}<br />
	spin_unlock(&#038;lslist_lock);<br />
	return NULL;<br />
}</p>
<p>static int dlm_scand(void *data)<br />
{<br />
	struct dlm_ls *ls;<br />
	int timeout_jiffies = dlm_config.ci_scan_secs * HZ;</p>
<p>	while (!kthread_should_stop()) {<br />
		ls = find_ls_to_scan();<br />
		if (ls) {<br />
			if (dlm_lock_recovery_try(ls)) {<br />
				ls->ls_scan_time = jiffies;<br />
				dlm_scan_rsbs(ls);<br />
				dlm_scan_timeout(ls);<br />
				dlm_unlock_recovery(ls);<br />
			} else {<br />
				ls->ls_scan_time += HZ;<br />
			}<br />
		} else {<br />
			schedule_timeout_interruptible(timeout_jiffies);<br />
		}<br />
	}<br />
	return 0;<br />
}</p>
<p>static int dlm_scand_start(void)<br />
{<br />
	struct task_struct *p;<br />
	int error = 0;</p>
<p>	p = kthread_run(dlm_scand, NULL, &laquo;dlm_scand&raquo;);<br />
	if (IS_ERR(p))<br />
		error = PTR_ERR(p);<br />
	else<br />
		scand_task = p;<br />
	return error;<br />
}</p>
<p>static void dlm_scand_stop(void)<br />
{<br />
	kthread_stop(scand_task);<br />
}</p>
<p>struct dlm_ls *dlm_find_lockspace_global(uint32_t id)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	spin_lock(&#038;lslist_lock);</p>
<p>	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		if (ls->ls_global_id == id) {<br />
			ls->ls_count++;<br />
			goto out;<br />
		}<br />
	}<br />
	ls = NULL;<br />
 out:<br />
	spin_unlock(&#038;lslist_lock);<br />
	return ls;<br />
}</p>
<p>struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		if (ls->ls_local_handle == lockspace) {<br />
			ls->ls_count++;<br />
			goto out;<br />
		}<br />
	}<br />
	ls = NULL;<br />
 out:<br />
	spin_unlock(&#038;lslist_lock);<br />
	return ls;<br />
}</p>
<p>struct dlm_ls *dlm_find_lockspace_device(int minor)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		if (ls->ls_device.minor == minor) {<br />
			ls->ls_count++;<br />
			goto out;<br />
		}<br />
	}<br />
	ls = NULL;<br />
 out:<br />
	spin_unlock(&#038;lslist_lock);<br />
	return ls;<br />
}</p>
<p>void dlm_put_lockspace(struct dlm_ls *ls)<br />
{<br />
	spin_lock(&#038;lslist_lock);<br />
	ls->ls_count&#8211;;<br />
	spin_unlock(&#038;lslist_lock);<br />
}</p>
<p>static void remove_lockspace(struct dlm_ls *ls)<br />
{<br />
	for (;;) {<br />
		spin_lock(&#038;lslist_lock);<br />
		if (ls->ls_count == 0) {<br />
			WARN_ON(ls->ls_create_count != 0);<br />
			list_del(&#038;ls->ls_list);<br />
			spin_unlock(&#038;lslist_lock);<br />
			return;<br />
		}<br />
		spin_unlock(&#038;lslist_lock);<br />
		ssleep(1);<br />
	}<br />
}</p>
<p>static int threads_start(void)<br />
{<br />
	int error;</p>
<p>	/* Thread which process lock requests for all lockspace&#8217;s */<br />
	error = dlm_astd_start();<br />
	if (error) {<br />
		log_print(&raquo;cannot start dlm_astd thread %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	error = dlm_scand_start();<br />
	if (error) {<br />
		log_print(&raquo;cannot start dlm_scand thread %d&raquo;, error);<br />
		goto astd_fail;<br />
	}</p>
<p>	/* Thread for sending/receiving messages for all lockspace&#8217;s */<br />
	error = dlm_lowcomms_start();<br />
	if (error) {<br />
		log_print(&raquo;cannot start dlm lowcomms %d&raquo;, error);<br />
		goto scand_fail;<br />
	}</p>
<p>	return 0;</p>
<p> scand_fail:<br />
	dlm_scand_stop();<br />
 astd_fail:<br />
	dlm_astd_stop();<br />
 fail:<br />
	return error;<br />
}</p>
<p>static void threads_stop(void)<br />
{<br />
	dlm_scand_stop();<br />
	dlm_lowcomms_stop();<br />
	dlm_astd_stop();<br />
}</p>
<p>static int new_lockspace(const char *name, int namelen, void **lockspace,<br />
			 uint32_t flags, int lvblen)<br />
{<br />
	struct dlm_ls *ls;<br />
	int i, size, error;<br />
	int do_unreg = 0;</p>
<p>	if (namelen > DLM_LOCKSPACE_LEN)<br />
		return -EINVAL;</p>
<p>	if (!lvblen || (lvblen % 8))<br />
		return -EINVAL;</p>
<p>	if (!try_module_get(THIS_MODULE))<br />
		return -EINVAL;</p>
<p>	if (!dlm_user_daemon_available()) {<br />
		module_put(THIS_MODULE);<br />
		return -EUNATCH;<br />
	}</p>
<p>	error = 0;</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		WARN_ON(ls->ls_create_count <= 0);<br />
		if (ls->ls_namelen != namelen)<br />
			continue;<br />
		if (memcmp(ls->ls_name, name, namelen))<br />
			continue;<br />
		if (flags &#038; DLM_LSFL_NEWEXCL) {<br />
			error = -EEXIST;<br />
			break;<br />
		}<br />
		ls->ls_create_count++;<br />
		*lockspace = ls;<br />
		error = 1;<br />
		break;<br />
	}<br />
	spin_unlock(&#038;lslist_lock);</p>
<p>	if (error)<br />
		goto out;</p>
<p>	error = -ENOMEM;</p>
<p>	ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);<br />
	if (!ls)<br />
		goto out;<br />
	memcpy(ls->ls_name, name, namelen);<br />
	ls->ls_namelen = namelen;<br />
	ls->ls_lvblen = lvblen;<br />
	ls->ls_count = 0;<br />
	ls->ls_flags = 0;<br />
	ls->ls_scan_time = jiffies;</p>
<p>	if (flags &#038; DLM_LSFL_TIMEWARN)<br />
		set_bit(LSFL_TIMEWARN, &#038;ls->ls_flags);</p>
<p>	if (flags &#038; DLM_LSFL_FS)<br />
		ls->ls_allocation = GFP_NOFS;<br />
	else<br />
		ls->ls_allocation = GFP_KERNEL;</p>
<p>	/* ls_exflags are forced to match among nodes, and we don&#8217;t<br />
	   need to require all nodes to have some flags set */<br />
	ls->ls_exflags = (flags &#038; ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS |<br />
				    DLM_LSFL_NEWEXCL));</p>
<p>	size = dlm_config.ci_rsbtbl_size;<br />
	ls->ls_rsbtbl_size = size;</p>
<p>	ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);<br />
	if (!ls->ls_rsbtbl)<br />
		goto out_lsfree;<br />
	for (i = 0; i < size; i++) {<br />
		INIT_LIST_HEAD(&#038;ls->ls_rsbtbl[i].list);<br />
		INIT_LIST_HEAD(&#038;ls->ls_rsbtbl[i].toss);<br />
		spin_lock_init(&#038;ls->ls_rsbtbl[i].lock);<br />
	}</p>
<p>	size = dlm_config.ci_lkbtbl_size;<br />
	ls->ls_lkbtbl_size = size;</p>
<p>	ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);<br />
	if (!ls->ls_lkbtbl)<br />
		goto out_rsbfree;<br />
	for (i = 0; i < size; i++) {<br />
		INIT_LIST_HEAD(&#038;ls->ls_lkbtbl[i].list);<br />
		rwlock_init(&#038;ls->ls_lkbtbl[i].lock);<br />
		ls->ls_lkbtbl[i].counter = 1;<br />
	}</p>
<p>	size = dlm_config.ci_dirtbl_size;<br />
	ls->ls_dirtbl_size = size;</p>
<p>	ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);<br />
	if (!ls->ls_dirtbl)<br />
		goto out_lkbfree;<br />
	for (i = 0; i < size; i++) {<br />
		INIT_LIST_HEAD(&#038;ls->ls_dirtbl[i].list);<br />
		spin_lock_init(&#038;ls->ls_dirtbl[i].lock);<br />
	}</p>
<p>	INIT_LIST_HEAD(&#038;ls->ls_waiters);<br />
	mutex_init(&#038;ls->ls_waiters_mutex);<br />
	INIT_LIST_HEAD(&#038;ls->ls_orphans);<br />
	mutex_init(&#038;ls->ls_orphans_mutex);<br />
	INIT_LIST_HEAD(&#038;ls->ls_timeout);<br />
	mutex_init(&#038;ls->ls_timeout_mutex);</p>
<p>	INIT_LIST_HEAD(&#038;ls->ls_nodes);<br />
	INIT_LIST_HEAD(&#038;ls->ls_nodes_gone);<br />
	ls->ls_num_nodes = 0;<br />
	ls->ls_low_nodeid = 0;<br />
	ls->ls_total_weight = 0;<br />
	ls->ls_node_array = NULL;</p>
<p>	memset(&#038;ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb));<br />
	ls->ls_stub_rsb.res_ls = ls;</p>
<p>	ls->ls_debug_rsb_dentry = NULL;<br />
	ls->ls_debug_waiters_dentry = NULL;</p>
<p>	init_waitqueue_head(&#038;ls->ls_uevent_wait);<br />
	ls->ls_uevent_result = 0;<br />
	init_completion(&#038;ls->ls_members_done);<br />
	ls->ls_members_result = -1;</p>
<p>	ls->ls_recoverd_task = NULL;<br />
	mutex_init(&#038;ls->ls_recoverd_active);<br />
	spin_lock_init(&#038;ls->ls_recover_lock);<br />
	spin_lock_init(&#038;ls->ls_rcom_spin);<br />
	get_random_bytes(&#038;ls->ls_rcom_seq, sizeof(uint64_t));<br />
	ls->ls_recover_status = 0;<br />
	ls->ls_recover_seq = 0;<br />
	ls->ls_recover_args = NULL;<br />
	init_rwsem(&#038;ls->ls_in_recovery);<br />
	init_rwsem(&#038;ls->ls_recv_active);<br />
	INIT_LIST_HEAD(&#038;ls->ls_requestqueue);<br />
	mutex_init(&#038;ls->ls_requestqueue_mutex);<br />
	mutex_init(&#038;ls->ls_clear_proc_locks);</p>
<p>	ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);<br />
	if (!ls->ls_recover_buf)<br />
		goto out_dirfree;</p>
<p>	INIT_LIST_HEAD(&#038;ls->ls_recover_list);<br />
	spin_lock_init(&#038;ls->ls_recover_list_lock);<br />
	ls->ls_recover_list_count = 0;<br />
	ls->ls_local_handle = ls;<br />
	init_waitqueue_head(&#038;ls->ls_wait_general);<br />
	INIT_LIST_HEAD(&#038;ls->ls_root_list);<br />
	init_rwsem(&#038;ls->ls_root_sem);</p>
<p>	down_write(&#038;ls->ls_in_recovery);</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	ls->ls_create_count = 1;<br />
	list_add(&#038;ls->ls_list, &#038;lslist);<br />
	spin_unlock(&#038;lslist_lock);</p>
<p>	/* needs to find ls in lslist */<br />
	error = dlm_recoverd_start(ls);<br />
	if (error) {<br />
		log_error(ls, &laquo;can&#8217;t start dlm_recoverd %d&raquo;, error);<br />
		goto out_delist;<br />
	}</p>
<p>	ls->ls_kobj.kset = dlm_kset;<br />
	error = kobject_init_and_add(&#038;ls->ls_kobj, &#038;dlm_ktype, NULL,<br />
				     &laquo;%s&raquo;, ls->ls_name);<br />
	if (error)<br />
		goto out_stop;<br />
	kobject_uevent(&#038;ls->ls_kobj, KOBJ_ADD);</p>
<p>	/* let kobject handle freeing of ls if there&#8217;s an error */<br />
	do_unreg = 1;</p>
<p>	/* This uevent triggers dlm_controld in userspace to add us to the<br />
	   group of nodes that are members of this lockspace (managed by the<br />
	   cluster infrastructure.)  Once it&#8217;s done that, it tells us who the<br />
	   current lockspace members are (via configfs) and then tells the<br />
	   lockspace to start running (via sysfs) in dlm_ls_start(). */</p>
<p>	error = do_uevent(ls, 1);<br />
	if (error)<br />
		goto out_stop;</p>
<p>	wait_for_completion(&#038;ls->ls_members_done);<br />
	error = ls->ls_members_result;<br />
	if (error)<br />
		goto out_members;</p>
<p>	dlm_create_debug_file(ls);</p>
<p>	log_debug(ls, &laquo;join complete&raquo;);<br />
	*lockspace = ls;<br />
	return 0;</p>
<p> out_members:<br />
	do_uevent(ls, 0);<br />
	dlm_clear_members(ls);<br />
	kfree(ls->ls_node_array);<br />
 out_stop:<br />
	dlm_recoverd_stop(ls);<br />
 out_delist:<br />
	spin_lock(&#038;lslist_lock);<br />
	list_del(&#038;ls->ls_list);<br />
	spin_unlock(&#038;lslist_lock);<br />
	kfree(ls->ls_recover_buf);<br />
 out_dirfree:<br />
	kfree(ls->ls_dirtbl);<br />
 out_lkbfree:<br />
	kfree(ls->ls_lkbtbl);<br />
 out_rsbfree:<br />
	kfree(ls->ls_rsbtbl);<br />
 out_lsfree:<br />
	if (do_unreg)<br />
		kobject_put(&#038;ls->ls_kobj);<br />
	else<br />
		kfree(ls);<br />
 out:<br />
	module_put(THIS_MODULE);<br />
	return error;<br />
}</p>
<p>int dlm_new_lockspace(const char *name, int namelen, void **lockspace,<br />
		      uint32_t flags, int lvblen)<br />
{<br />
	int error = 0;</p>
<p>	mutex_lock(&#038;ls_lock);<br />
	if (!ls_count)<br />
		error = threads_start();<br />
	if (error)<br />
		goto out;</p>
<p>	error = new_lockspace(name, namelen, lockspace, flags, lvblen);<br />
	if (!error)<br />
		ls_count++;<br />
	if (error > 0)<br />
		error = 0;<br />
	if (!ls_count)<br />
		threads_stop();<br />
 out:<br />
	mutex_unlock(&#038;ls_lock);<br />
	return error;<br />
}</p>
<p>/* Return 1 if the lockspace still has active remote locks,<br />
 *        2 if the lockspace still has active local locks.<br />
 */<br />
static int lockspace_busy(struct dlm_ls *ls)<br />
{<br />
	int i, lkb_found = 0;<br />
	struct dlm_lkb *lkb;</p>
<p>	/* NOTE: We check the lockidtbl here rather than the resource table.<br />
	   This is because there may be LKBs queued as ASTs that have been<br />
	   unlinked from their RSBs and are pending deletion once the AST has<br />
	   been delivered */</p>
<p>	for (i = 0; i < ls->ls_lkbtbl_size; i++) {<br />
		read_lock(&#038;ls->ls_lkbtbl[i].lock);<br />
		if (!list_empty(&#038;ls->ls_lkbtbl[i].list)) {<br />
			lkb_found = 1;<br />
			list_for_each_entry(lkb, &#038;ls->ls_lkbtbl[i].list,<br />
					    lkb_idtbl_list) {<br />
				if (!lkb->lkb_nodeid) {<br />
					read_unlock(&#038;ls->ls_lkbtbl[i].lock);<br />
					return 2;<br />
				}<br />
			}<br />
		}<br />
		read_unlock(&#038;ls->ls_lkbtbl[i].lock);<br />
	}<br />
	return lkb_found;<br />
}</p>
<p>static int release_lockspace(struct dlm_ls *ls, int force)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *rsb;<br />
	struct list_head *head;<br />
	int i, busy, rv;</p>
<p>	busy = lockspace_busy(ls);</p>
<p>	spin_lock(&#038;lslist_lock);<br />
	if (ls->ls_create_count == 1) {<br />
		if (busy > force)<br />
			rv = -EBUSY;<br />
		else {<br />
			/* remove_lockspace takes ls off lslist */<br />
			ls->ls_create_count = 0;<br />
			rv = 0;<br />
		}<br />
	} else if (ls->ls_create_count > 1) {<br />
		rv = &#8211;ls->ls_create_count;<br />
	} else {<br />
		rv = -EINVAL;<br />
	}<br />
	spin_unlock(&#038;lslist_lock);</p>
<p>	if (rv) {<br />
		log_debug(ls, &laquo;release_lockspace no remove %d&raquo;, rv);<br />
		return rv;<br />
	}</p>
<p>	dlm_device_deregister(ls);</p>
<p>	if (force < 3 &#038;&#038; dlm_user_daemon_available())<br />
		do_uevent(ls, 0);</p>
<p>	dlm_recoverd_stop(ls);</p>
<p>	remove_lockspace(ls);</p>
<p>	dlm_delete_debug_file(ls);</p>
<p>	dlm_astd_suspend();</p>
<p>	kfree(ls->ls_recover_buf);</p>
<p>	/*<br />
	 * Free direntry structs.<br />
	 */</p>
<p>	dlm_dir_clear(ls);<br />
	kfree(ls->ls_dirtbl);</p>
<p>	/*<br />
	 * Free all lkb&#8217;s on lkbtbl[] lists.<br />
	 */</p>
<p>	for (i = 0; i < ls->ls_lkbtbl_size; i++) {<br />
		head = &#038;ls->ls_lkbtbl[i].list;<br />
		while (!list_empty(head)) {<br />
			lkb = list_entry(head->next, struct dlm_lkb,<br />
					 lkb_idtbl_list);</p>
<p>			list_del(&#038;lkb->lkb_idtbl_list);</p>
<p>			dlm_del_ast(lkb);</p>
<p>			if (lkb->lkb_lvbptr &#038;&#038; lkb->lkb_flags &#038; DLM_IFL_MSTCPY)<br />
				dlm_free_lvb(lkb->lkb_lvbptr);</p>
<p>			dlm_free_lkb(lkb);<br />
		}<br />
	}<br />
	dlm_astd_resume();</p>
<p>	kfree(ls->ls_lkbtbl);</p>
<p>	/*<br />
	 * Free all rsb&#8217;s on rsbtbl[] lists<br />
	 */</p>
<p>	for (i = 0; i < ls->ls_rsbtbl_size; i++) {<br />
		head = &#038;ls->ls_rsbtbl[i].list;<br />
		while (!list_empty(head)) {<br />
			rsb = list_entry(head->next, struct dlm_rsb,<br />
					 res_hashchain);</p>
<p>			list_del(&#038;rsb->res_hashchain);<br />
			dlm_free_rsb(rsb);<br />
		}</p>
<p>		head = &#038;ls->ls_rsbtbl[i].toss;<br />
		while (!list_empty(head)) {<br />
			rsb = list_entry(head->next, struct dlm_rsb,<br />
					 res_hashchain);<br />
			list_del(&#038;rsb->res_hashchain);<br />
			dlm_free_rsb(rsb);<br />
		}<br />
	}</p>
<p>	kfree(ls->ls_rsbtbl);</p>
<p>	/*<br />
	 * Free structures on any other lists<br />
	 */</p>
<p>	dlm_purge_requestqueue(ls);<br />
	kfree(ls->ls_recover_args);<br />
	dlm_clear_free_entries(ls);<br />
	dlm_clear_members(ls);<br />
	dlm_clear_members_gone(ls);<br />
	kfree(ls->ls_node_array);<br />
	log_debug(ls, &laquo;release_lockspace final free&raquo;);<br />
	kobject_put(&#038;ls->ls_kobj);<br />
	/* The ls structure will be freed when the kobject is done with */</p>
<p>	module_put(THIS_MODULE);<br />
	return 0;<br />
}</p>
<p>/*<br />
 * Called when a system has released all its locks and is not going to use the<br />
 * lockspace any longer.  We free everything we&#8217;re managing for this lockspace.<br />
 * Remaining nodes will go through the recovery process as if we&#8217;d died.  The<br />
 * lockspace must continue to function as usual, participating in recoveries,<br />
 * until this returns.<br />
 *<br />
 * Force has 4 possible values:<br />
 * 0 &#8211; don&#8217;t destroy locksapce if it has any LKBs<br />
 * 1 &#8211; destroy lockspace if it has remote LKBs but not if it has local LKBs<br />
 * 2 &#8211; destroy lockspace regardless of LKBs<br />
 * 3 &#8211; destroy lockspace as part of a forced shutdown<br />
 */</p>
<p>int dlm_release_lockspace(void *lockspace, int force)<br />
{<br />
	struct dlm_ls *ls;<br />
	int error;</p>
<p>	ls = dlm_find_lockspace_local(lockspace);<br />
	if (!ls)<br />
		return -EINVAL;<br />
	dlm_put_lockspace(ls);</p>
<p>	mutex_lock(&#038;ls_lock);<br />
	error = release_lockspace(ls, force);<br />
	if (!error)<br />
		ls_count&#8211;;<br />
	if (!ls_count)<br />
		threads_stop();<br />
	mutex_unlock(&#038;ls_lock);</p>
<p>	return error;<br />
}</p>
<p>void dlm_stop_lockspaces(void)<br />
{<br />
	struct dlm_ls *ls;</p>
<p> restart:<br />
	spin_lock(&#038;lslist_lock);<br />
	list_for_each_entry(ls, &#038;lslist, ls_list) {<br />
		if (!test_bit(LSFL_RUNNING, &#038;ls->ls_flags))<br />
			continue;<br />
		spin_unlock(&#038;lslist_lock);<br />
		log_error(ls, &laquo;no userland control daemon, stopping lockspace&raquo;);<br />
		dlm_ls_stop(ls);<br />
		goto restart;<br />
	}<br />
	spin_unlock(&#038;lslist_lock);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lockspace-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lock.h</title>
		<link>http://lynyrd.ru/lock-h</link>
		<comments>http://lynyrd.ru/lock-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:50:20 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/lock-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#ifndef __LOCK_DOT_H__
#define __LOCK_DOT_H__
void dlm_dump_rsb(struct dlm_rsb *r);
void dlm_print_lkb(struct dlm_lkb *lkb);
void dlm_receive_message_saved(struct dlm_ls *ls, ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.<span id="more-1034"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __LOCK_DOT_H__<br />
#define __LOCK_DOT_H__</p>
<p>void dlm_dump_rsb(struct dlm_rsb *r);<br />
void dlm_print_lkb(struct dlm_lkb *lkb);<br />
void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);<br />
void dlm_receive_buffer(union dlm_packet *p, int nodeid);<br />
int dlm_modes_compat(int mode1, int mode2);<br />
void dlm_put_rsb(struct dlm_rsb *r);<br />
void dlm_hold_rsb(struct dlm_rsb *r);<br />
int dlm_put_lkb(struct dlm_lkb *lkb);<br />
void dlm_scan_rsbs(struct dlm_ls *ls);<br />
int dlm_lock_recovery_try(struct dlm_ls *ls);<br />
void dlm_unlock_recovery(struct dlm_ls *ls);<br />
void dlm_scan_timeout(struct dlm_ls *ls);<br />
void dlm_adjust_timeouts(struct dlm_ls *ls);</p>
<p>int dlm_purge_locks(struct dlm_ls *ls);<br />
void dlm_purge_mstcpy_locks(struct dlm_rsb *r);<br />
void dlm_grant_after_purge(struct dlm_ls *ls);<br />
int dlm_recover_waiters_post(struct dlm_ls *ls);<br />
void dlm_recover_waiters_pre(struct dlm_ls *ls);<br />
int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);<br />
int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);</p>
<p>int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,<br />
	uint32_t flags, void *name, unsigned int namelen,<br />
	unsigned long timeout_cs);<br />
int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,<br />
	int mode, uint32_t flags, uint32_t lkid, char *lvb_in,<br />
	unsigned long timeout_cs);<br />
int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,<br />
	uint32_t flags, uint32_t lkid, char *lvb_in);<br />
int dlm_user_cancel(struct dlm_ls *ls,  struct dlm_user_args *ua_tmp,<br />
	uint32_t flags, uint32_t lkid);<br />
int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,<br />
	int nodeid, int pid);<br />
int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid);<br />
void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);</p>
<p>static inline int is_master(struct dlm_rsb *r)<br />
{<br />
	return !r->res_nodeid;<br />
}</p>
<p>static inline void lock_rsb(struct dlm_rsb *r)<br />
{<br />
	mutex_lock(&#038;r->res_mutex);<br />
}</p>
<p>static inline void unlock_rsb(struct dlm_rsb *r)<br />
{<br />
	mutex_unlock(&#038;r->res_mutex);<br />
}</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lock-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lock.c</title>
		<link>http://lynyrd.ru/lock-c</link>
		<comments>http://lynyrd.ru/lock-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:50:02 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/lock-c</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2008 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.
**
*******************************************************************************
******************************************************************************/
/* Central locking logic has four stages:
   dlm_lock()
   ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.<span id="more-1033"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>/* Central locking logic has four stages:</p>
<p>   dlm_lock()<br />
   dlm_unlock()</p>
<p>   request_lock(ls, lkb)<br />
   convert_lock(ls, lkb)<br />
   unlock_lock(ls, lkb)<br />
   cancel_lock(ls, lkb)</p>
<p>   _request_lock(r, lkb)<br />
   _convert_lock(r, lkb)<br />
   _unlock_lock(r, lkb)<br />
   _cancel_lock(r, lkb)</p>
<p>   do_request(r, lkb)<br />
   do_convert(r, lkb)<br />
   do_unlock(r, lkb)<br />
   do_cancel(r, lkb)</p>
<p>   Stage 1 (lock, unlock) is mainly about checking input args and<br />
   splitting into one of the four main operations:</p>
<p>       dlm_lock          = request_lock<br />
       dlm_lock+CONVERT  = convert_lock<br />
       dlm_unlock        = unlock_lock<br />
       dlm_unlock+CANCEL = cancel_lock</p>
<p>   Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is<br />
   provided to the next stage.</p>
<p>   Stage 3, _xxxx_lock(), determines if the operation is local or remote.<br />
   When remote, it calls send_xxxx(), when local it calls do_xxxx().</p>
<p>   Stage 4, do_xxxx(), is the guts of the operation.  It manipulates the<br />
   given rsb and lkb and queues callbacks.</p>
<p>   For remote operations, send_xxxx() results in the corresponding do_xxxx()<br />
   function being executed on the remote node.  The connecting send/receive<br />
   calls on local (L) and remote (R) nodes:</p>
<p>   L: send_xxxx()              ->  R: receive_xxxx()<br />
                                   R: do_xxxx()<br />
   L: receive_xxxx_reply()     <-  R: send_xxxx_reply()<br />
*/<br />
#include
<linux/types.h>
#include &laquo;dlm_internal.h&raquo;<br />
#include
<linux/dlm_device.h>
#include &laquo;memory.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;requestqueue.h&raquo;<br />
#include &laquo;util.h&raquo;<br />
#include &laquo;dir.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;ast.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;rcom.h&raquo;<br />
#include &laquo;recover.h&raquo;<br />
#include &laquo;lvb_table.h&raquo;<br />
#include &laquo;user.h&raquo;<br />
#include &laquo;config.h&raquo;</p>
<p>static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);<br />
static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int send_remove(struct dlm_rsb *r);<br />
static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
				    struct dlm_message *ms);<br />
static int receive_extralen(struct dlm_message *ms);<br />
static void do_purge(struct dlm_ls *ls, int nodeid, int pid);<br />
static void del_timeout(struct dlm_lkb *lkb);</p>
<p>/*<br />
 * Lock compatibilty matrix &#8211; thanks Steve<br />
 * UN = Unlocked state. Not really a state, used as a flag<br />
 * PD = Padding. Used to make the matrix a nice power of two in size<br />
 * Other states are the same as the VMS DLM.<br />
 * Usage: matrix[grmode+1][rqmode+1]  (although m[rq+1][gr+1] is the same)<br />
 */</p>
<p>static const int __dlm_compat_matrix[8][8] = {<br />
      /* UN NL CR CW PR PW EX PD */<br />
        {1, 1, 1, 1, 1, 1, 1, 0},       /* UN */<br />
        {1, 1, 1, 1, 1, 1, 1, 0},       /* NL */<br />
        {1, 1, 1, 1, 1, 1, 0, 0},       /* CR */<br />
        {1, 1, 1, 1, 0, 0, 0, 0},       /* CW */<br />
        {1, 1, 1, 0, 1, 0, 0, 0},       /* PR */<br />
        {1, 1, 1, 0, 0, 0, 0, 0},       /* PW */<br />
        {1, 1, 0, 0, 0, 0, 0, 0},       /* EX */<br />
        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */<br />
};</p>
<p>/*<br />
 * This defines the direction of transfer of LVB data.<br />
 * Granted mode is the row; requested mode is the column.<br />
 * Usage: matrix[grmode+1][rqmode+1]<br />
 * 1 = LVB is returned to the caller<br />
 * 0 = LVB is written to the resource<br />
 * -1 = nothing happens to the LVB<br />
 */</p>
<p>const int dlm_lvb_operations[8][8] = {<br />
        /* UN   NL  CR  CW  PR  PW  EX  PD*/<br />
        {  -1,  1,  1,  1,  1,  1,  1, -1 }, /* UN */<br />
        {  -1,  1,  1,  1,  1,  1,  1,  0 }, /* NL */<br />
        {  -1, -1,  1,  1,  1,  1,  1,  0 }, /* CR */<br />
        {  -1, -1, -1,  1,  1,  1,  1,  0 }, /* CW */<br />
        {  -1, -1, -1, -1,  1,  1,  1,  0 }, /* PR */<br />
        {  -1,  0,  0,  0,  0,  0,  1,  0 }, /* PW */<br />
        {  -1,  0,  0,  0,  0,  0,  0,  0 }, /* EX */<br />
        {  -1,  0,  0,  0,  0,  0,  0,  0 }  /* PD */<br />
};</p>
<p>#define modes_compat(gr, rq) \<br />
	__dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]</p>
<p>int dlm_modes_compat(int mode1, int mode2)<br />
{<br />
	return __dlm_compat_matrix[mode1 + 1][mode2 + 1];<br />
}</p>
<p>/*<br />
 * Compatibility matrix for conversions with QUECVT set.<br />
 * Granted mode is the row; requested mode is the column.<br />
 * Usage: matrix[grmode+1][rqmode+1]<br />
 */</p>
<p>static const int __quecvt_compat_matrix[8][8] = {<br />
      /* UN NL CR CW PR PW EX PD */<br />
        {0, 0, 0, 0, 0, 0, 0, 0},       /* UN */<br />
        {0, 0, 1, 1, 1, 1, 1, 0},       /* NL */<br />
        {0, 0, 0, 1, 1, 1, 1, 0},       /* CR */<br />
        {0, 0, 0, 0, 1, 1, 1, 0},       /* CW */<br />
        {0, 0, 0, 1, 0, 1, 1, 0},       /* PR */<br />
        {0, 0, 0, 0, 0, 0, 1, 0},       /* PW */<br />
        {0, 0, 0, 0, 0, 0, 0, 0},       /* EX */<br />
        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */<br />
};</p>
<p>void dlm_print_lkb(struct dlm_lkb *lkb)<br />
{<br />
	printk(KERN_ERR &laquo;lkb: nodeid %d id %x remid %x exflags %x flags %x\n&raquo;<br />
	       &raquo;     status %d rqmode %d grmode %d wait_type %d ast_type %d\n&raquo;,<br />
	       lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,<br />
	       lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,<br />
	       lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);<br />
}</p>
<p>static void dlm_print_rsb(struct dlm_rsb *r)<br />
{<br />
	printk(KERN_ERR &laquo;rsb: nodeid %d flags %lx first %x rlc %d name %s\n&raquo;,<br />
	       r->res_nodeid, r->res_flags, r->res_first_lkid,<br />
	       r->res_recover_locks_count, r->res_name);<br />
}</p>
<p>void dlm_dump_rsb(struct dlm_rsb *r)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	dlm_print_rsb(r);</p>
<p>	printk(KERN_ERR &laquo;rsb: root_list empty %d recover_list empty %d\n&raquo;,<br />
	       list_empty(&#038;r->res_root_list), list_empty(&#038;r->res_recover_list));<br />
	printk(KERN_ERR &laquo;rsb lookup list\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;r->res_lookup, lkb_rsb_lookup)<br />
		dlm_print_lkb(lkb);<br />
	printk(KERN_ERR &laquo;rsb grant queue:\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;r->res_grantqueue, lkb_statequeue)<br />
		dlm_print_lkb(lkb);<br />
	printk(KERN_ERR &laquo;rsb convert queue:\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;r->res_convertqueue, lkb_statequeue)<br />
		dlm_print_lkb(lkb);<br />
	printk(KERN_ERR &laquo;rsb wait queue:\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;r->res_waitqueue, lkb_statequeue)<br />
		dlm_print_lkb(lkb);<br />
}</p>
<p>/* Threads cannot use the lockspace while it&#8217;s being recovered */</p>
<p>static inline void dlm_lock_recovery(struct dlm_ls *ls)<br />
{<br />
	down_read(&#038;ls->ls_in_recovery);<br />
}</p>
<p>void dlm_unlock_recovery(struct dlm_ls *ls)<br />
{<br />
	up_read(&#038;ls->ls_in_recovery);<br />
}</p>
<p>int dlm_lock_recovery_try(struct dlm_ls *ls)<br />
{<br />
	return down_read_trylock(&#038;ls->ls_in_recovery);<br />
}</p>
<p>static inline int can_be_queued(struct dlm_lkb *lkb)<br />
{<br />
	return !(lkb->lkb_exflags &#038; DLM_LKF_NOQUEUE);<br />
}</p>
<p>static inline int force_blocking_asts(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_exflags &#038; DLM_LKF_NOQUEUEBAST);<br />
}</p>
<p>static inline int is_demoted(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_sbflags &#038; DLM_SBF_DEMOTED);<br />
}</p>
<p>static inline int is_altmode(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_sbflags &#038; DLM_SBF_ALTMODE);<br />
}</p>
<p>static inline int is_granted(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_status == DLM_LKSTS_GRANTED);<br />
}</p>
<p>static inline int is_remote(struct dlm_rsb *r)<br />
{<br />
	DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););<br />
	return !!r->res_nodeid;<br />
}</p>
<p>static inline int is_process_copy(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_nodeid &#038;&#038; !(lkb->lkb_flags &#038; DLM_IFL_MSTCPY));<br />
}</p>
<p>static inline int is_master_copy(struct dlm_lkb *lkb)<br />
{<br />
	if (lkb->lkb_flags &#038; DLM_IFL_MSTCPY)<br />
		DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););<br />
	return (lkb->lkb_flags &#038; DLM_IFL_MSTCPY) ? 1 : 0;<br />
}</p>
<p>static inline int middle_conversion(struct dlm_lkb *lkb)<br />
{<br />
	if ((lkb->lkb_grmode==DLM_LOCK_PR &#038;&#038; lkb->lkb_rqmode==DLM_LOCK_CW) ||<br />
	    (lkb->lkb_rqmode==DLM_LOCK_PR &#038;&#038; lkb->lkb_grmode==DLM_LOCK_CW))<br />
		return 1;<br />
	return 0;<br />
}</p>
<p>static inline int down_conversion(struct dlm_lkb *lkb)<br />
{<br />
	return (!middle_conversion(lkb) &#038;&#038; lkb->lkb_rqmode < lkb->lkb_grmode);<br />
}</p>
<p>static inline int is_overlap_unlock(struct dlm_lkb *lkb)<br />
{<br />
	return lkb->lkb_flags &#038; DLM_IFL_OVERLAP_UNLOCK;<br />
}</p>
<p>static inline int is_overlap_cancel(struct dlm_lkb *lkb)<br />
{<br />
	return lkb->lkb_flags &#038; DLM_IFL_OVERLAP_CANCEL;<br />
}</p>
<p>static inline int is_overlap(struct dlm_lkb *lkb)<br />
{<br />
	return (lkb->lkb_flags &#038; (DLM_IFL_OVERLAP_UNLOCK |<br />
				  DLM_IFL_OVERLAP_CANCEL));<br />
}</p>
<p>static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)<br />
{<br />
	if (is_master_copy(lkb))<br />
		return;</p>
<p>	del_timeout(lkb);</p>
<p>	DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););</p>
<p>	/* if the operation was a cancel, then return -DLM_ECANCEL, if a<br />
	   timeout caused the cancel then return -ETIMEDOUT */<br />
	if (rv == -DLM_ECANCEL &#038;&#038; (lkb->lkb_flags &#038; DLM_IFL_TIMEOUT_CANCEL)) {<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_TIMEOUT_CANCEL;<br />
		rv = -ETIMEDOUT;<br />
	}</p>
<p>	if (rv == -DLM_ECANCEL &#038;&#038; (lkb->lkb_flags &#038; DLM_IFL_DEADLOCK_CANCEL)) {<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_DEADLOCK_CANCEL;<br />
		rv = -EDEADLK;<br />
	}</p>
<p>	lkb->lkb_lksb->sb_status = rv;<br />
	lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;</p>
<p>	dlm_add_ast(lkb, AST_COMP, 0);<br />
}</p>
<p>static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	queue_cast(r, lkb,<br />
		   is_overlap_unlock(lkb) ? -DLM_EUNLOCK : -DLM_ECANCEL);<br />
}</p>
<p>static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)<br />
{<br />
	lkb->lkb_time_bast = ktime_get();</p>
<p>	if (is_master_copy(lkb))<br />
		send_bast(r, lkb, rqmode);<br />
	else<br />
		dlm_add_ast(lkb, AST_BAST, rqmode);<br />
}</p>
<p>/*<br />
 * Basic operations on rsb&#8217;s and lkb&#8217;s<br />
 */</p>
<p>static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len)<br />
{<br />
	struct dlm_rsb *r;</p>
<p>	r = dlm_allocate_rsb(ls, len);<br />
	if (!r)<br />
		return NULL;</p>
<p>	r->res_ls = ls;<br />
	r->res_length = len;<br />
	memcpy(r->res_name, name, len);<br />
	mutex_init(&#038;r->res_mutex);</p>
<p>	INIT_LIST_HEAD(&#038;r->res_lookup);<br />
	INIT_LIST_HEAD(&#038;r->res_grantqueue);<br />
	INIT_LIST_HEAD(&#038;r->res_convertqueue);<br />
	INIT_LIST_HEAD(&#038;r->res_waitqueue);<br />
	INIT_LIST_HEAD(&#038;r->res_root_list);<br />
	INIT_LIST_HEAD(&#038;r->res_recover_list);</p>
<p>	return r;<br />
}</p>
<p>static int search_rsb_list(struct list_head *head, char *name, int len,<br />
			   unsigned int flags, struct dlm_rsb **r_ret)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error = 0;</p>
<p>	list_for_each_entry(r, head, res_hashchain) {<br />
		if (len == r->res_length &#038;&#038; !memcmp(name, r->res_name, len))<br />
			goto found;<br />
	}<br />
	*r_ret = NULL;<br />
	return -EBADR;</p>
<p> found:<br />
	if (r->res_nodeid &#038;&#038; (flags &#038; R_MASTER))<br />
		error = -ENOTBLK;<br />
	*r_ret = r;<br />
	return error;<br />
}</p>
<p>static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,<br />
		       unsigned int flags, struct dlm_rsb **r_ret)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = search_rsb_list(&#038;ls->ls_rsbtbl[b].list, name, len, flags, &#038;r);<br />
	if (!error) {<br />
		kref_get(&#038;r->res_ref);<br />
		goto out;<br />
	}<br />
	error = search_rsb_list(&#038;ls->ls_rsbtbl[b].toss, name, len, flags, &#038;r);<br />
	if (error)<br />
		goto out;</p>
<p>	list_move(&#038;r->res_hashchain, &#038;ls->ls_rsbtbl[b].list);</p>
<p>	if (dlm_no_directory(ls))<br />
		goto out;</p>
<p>	if (r->res_nodeid == -1) {<br />
		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);<br />
		r->res_first_lkid = 0;<br />
	} else if (r->res_nodeid > 0) {<br />
		rsb_set_flag(r, RSB_MASTER_UNCERTAIN);<br />
		r->res_first_lkid = 0;<br />
	} else {<br />
		DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););<br />
		DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);<br />
	}<br />
 out:<br />
	*r_ret = r;<br />
	return error;<br />
}</p>
<p>static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,<br />
		      unsigned int flags, struct dlm_rsb **r_ret)<br />
{<br />
	int error;<br />
	spin_lock(&#038;ls->ls_rsbtbl[b].lock);<br />
	error = _search_rsb(ls, name, len, b, flags, r_ret);<br />
	spin_unlock(&#038;ls->ls_rsbtbl[b].lock);<br />
	return error;<br />
}</p>
<p>/*<br />
 * Find rsb in rsbtbl and potentially create/add one<br />
 *<br />
 * Delaying the release of rsb&#8217;s has a similar benefit to applications keeping<br />
 * NL locks on an rsb, but without the guarantee that the cached master value<br />
 * will still be valid when the rsb is reused.  Apps aren&#8217;t always smart enough<br />
 * to keep NL locks on an rsb that they may lock again shortly; this can lead<br />
 * to excessive master lookups and removals if we don&#8217;t delay the release.<br />
 *<br />
 * Searching for an rsb means looking through both the normal list and toss<br />
 * list.  When found on the toss list the rsb is moved to the normal list with<br />
 * ref count of 1; when found on normal list the ref count is incremented.<br />
 */</p>
<p>static int find_rsb(struct dlm_ls *ls, char *name, int namelen,<br />
		    unsigned int flags, struct dlm_rsb **r_ret)<br />
{<br />
	struct dlm_rsb *r = NULL, *tmp;<br />
	uint32_t hash, bucket;<br />
	int error = -EINVAL;</p>
<p>	if (namelen > DLM_RESNAME_MAXLEN)<br />
		goto out;</p>
<p>	if (dlm_no_directory(ls))<br />
		flags |= R_CREATE;</p>
<p>	error = 0;<br />
	hash = jhash(name, namelen, 0);<br />
	bucket = hash &#038; (ls->ls_rsbtbl_size &#8211; 1);</p>
<p>	error = search_rsb(ls, name, namelen, bucket, flags, &#038;r);<br />
	if (!error)<br />
		goto out;</p>
<p>	if (error == -EBADR &#038;&#038; !(flags &#038; R_CREATE))<br />
		goto out;</p>
<p>	/* the rsb was found but wasn&#8217;t a master copy */<br />
	if (error == -ENOTBLK)<br />
		goto out;</p>
<p>	error = -ENOMEM;<br />
	r = create_rsb(ls, name, namelen);<br />
	if (!r)<br />
		goto out;</p>
<p>	r->res_hash = hash;<br />
	r->res_bucket = bucket;<br />
	r->res_nodeid = -1;<br />
	kref_init(&#038;r->res_ref);</p>
<p>	/* With no directory, the master can be set immediately */<br />
	if (dlm_no_directory(ls)) {<br />
		int nodeid = dlm_dir_nodeid(r);<br />
		if (nodeid == dlm_our_nodeid())<br />
			nodeid = 0;<br />
		r->res_nodeid = nodeid;<br />
	}</p>
<p>	spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	error = _search_rsb(ls, name, namelen, bucket, 0, &#038;tmp);<br />
	if (!error) {<br />
		spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
		dlm_free_rsb(r);<br />
		r = tmp;<br />
		goto out;<br />
	}<br />
	list_add(&#038;r->res_hashchain, &#038;ls->ls_rsbtbl[bucket].list);<br />
	spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	error = 0;<br />
 out:<br />
	*r_ret = r;<br />
	return error;<br />
}</p>
<p>/* This is only called to add a reference when the code already holds<br />
   a valid reference to the rsb, so there&#8217;s no need for locking. */</p>
<p>static inline void hold_rsb(struct dlm_rsb *r)<br />
{<br />
	kref_get(&#038;r->res_ref);<br />
}</p>
<p>void dlm_hold_rsb(struct dlm_rsb *r)<br />
{<br />
	hold_rsb(r);<br />
}</p>
<p>static void toss_rsb(struct kref *kref)<br />
{<br />
	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);<br />
	struct dlm_ls *ls = r->res_ls;</p>
<p>	DLM_ASSERT(list_empty(&#038;r->res_root_list), dlm_print_rsb(r););<br />
	kref_init(&#038;r->res_ref);<br />
	list_move(&#038;r->res_hashchain, &#038;ls->ls_rsbtbl[r->res_bucket].toss);<br />
	r->res_toss_time = jiffies;<br />
	if (r->res_lvbptr) {<br />
		dlm_free_lvb(r->res_lvbptr);<br />
		r->res_lvbptr = NULL;<br />
	}<br />
}</p>
<p>/* When all references to the rsb are gone it&#8217;s transfered to<br />
   the tossed list for later disposal. */</p>
<p>static void put_rsb(struct dlm_rsb *r)<br />
{<br />
	struct dlm_ls *ls = r->res_ls;<br />
	uint32_t bucket = r->res_bucket;</p>
<p>	spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	kref_put(&#038;r->res_ref, toss_rsb);<br />
	spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
}</p>
<p>void dlm_put_rsb(struct dlm_rsb *r)<br />
{<br />
	put_rsb(r);<br />
}</p>
<p>/* See comment for unhold_lkb */</p>
<p>static void unhold_rsb(struct dlm_rsb *r)<br />
{<br />
	int rv;<br />
	rv = kref_put(&#038;r->res_ref, toss_rsb);<br />
	DLM_ASSERT(!rv, dlm_dump_rsb(r););<br />
}</p>
<p>static void kill_rsb(struct kref *kref)<br />
{<br />
	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);</p>
<p>	/* All work is done after the return from kref_put() so we<br />
	   can release the write_lock before the remove and free. */</p>
<p>	DLM_ASSERT(list_empty(&#038;r->res_lookup), dlm_dump_rsb(r););<br />
	DLM_ASSERT(list_empty(&#038;r->res_grantqueue), dlm_dump_rsb(r););<br />
	DLM_ASSERT(list_empty(&#038;r->res_convertqueue), dlm_dump_rsb(r););<br />
	DLM_ASSERT(list_empty(&#038;r->res_waitqueue), dlm_dump_rsb(r););<br />
	DLM_ASSERT(list_empty(&#038;r->res_root_list), dlm_dump_rsb(r););<br />
	DLM_ASSERT(list_empty(&#038;r->res_recover_list), dlm_dump_rsb(r););<br />
}</p>
<p>/* Attaching/detaching lkb&#8217;s from rsb&#8217;s is for rsb reference counting.<br />
   The rsb must exist as long as any lkb&#8217;s for it do. */</p>
<p>static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	hold_rsb(r);<br />
	lkb->lkb_resource = r;<br />
}</p>
<p>static void detach_lkb(struct dlm_lkb *lkb)<br />
{<br />
	if (lkb->lkb_resource) {<br />
		put_rsb(lkb->lkb_resource);<br />
		lkb->lkb_resource = NULL;<br />
	}<br />
}</p>
<p>static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)<br />
{<br />
	struct dlm_lkb *lkb, *tmp;<br />
	uint32_t lkid = 0;<br />
	uint16_t bucket;</p>
<p>	lkb = dlm_allocate_lkb(ls);<br />
	if (!lkb)<br />
		return -ENOMEM;</p>
<p>	lkb->lkb_nodeid = -1;<br />
	lkb->lkb_grmode = DLM_LOCK_IV;<br />
	kref_init(&#038;lkb->lkb_ref);<br />
	INIT_LIST_HEAD(&#038;lkb->lkb_ownqueue);<br />
	INIT_LIST_HEAD(&#038;lkb->lkb_rsb_lookup);<br />
	INIT_LIST_HEAD(&#038;lkb->lkb_time_list);</p>
<p>	get_random_bytes(&#038;bucket, sizeof(bucket));<br />
	bucket &#038;= (ls->ls_lkbtbl_size &#8211; 1);</p>
<p>	write_lock(&#038;ls->ls_lkbtbl[bucket].lock);</p>
<p>	/* counter can roll over so we must verify lkid is not in use */</p>
<p>	while (lkid == 0) {<br />
		lkid = (bucket << 16) | ls->ls_lkbtbl[bucket].counter++;</p>
<p>		list_for_each_entry(tmp, &#038;ls->ls_lkbtbl[bucket].list,<br />
				    lkb_idtbl_list) {<br />
			if (tmp->lkb_id != lkid)<br />
				continue;<br />
			lkid = 0;<br />
			break;<br />
		}<br />
	}</p>
<p>	lkb->lkb_id = lkid;<br />
	list_add(&#038;lkb->lkb_idtbl_list, &#038;ls->ls_lkbtbl[bucket].list);<br />
	write_unlock(&#038;ls->ls_lkbtbl[bucket].lock);</p>
<p>	*lkb_ret = lkb;<br />
	return 0;<br />
}</p>
<p>static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	uint16_t bucket = (lkid >> 16);</p>
<p>	list_for_each_entry(lkb, &#038;ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {<br />
		if (lkb->lkb_id == lkid)<br />
			return lkb;<br />
	}<br />
	return NULL;<br />
}</p>
<p>static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	uint16_t bucket = (lkid >> 16);</p>
<p>	if (bucket >= ls->ls_lkbtbl_size)<br />
		return -EBADSLT;</p>
<p>	read_lock(&#038;ls->ls_lkbtbl[bucket].lock);<br />
	lkb = __find_lkb(ls, lkid);<br />
	if (lkb)<br />
		kref_get(&#038;lkb->lkb_ref);<br />
	read_unlock(&#038;ls->ls_lkbtbl[bucket].lock);</p>
<p>	*lkb_ret = lkb;<br />
	return lkb ? 0 : -ENOENT;<br />
}</p>
<p>static void kill_lkb(struct kref *kref)<br />
{<br />
	struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);</p>
<p>	/* All work is done after the return from kref_put() so we<br />
	   can release the write_lock before the detach_lkb */</p>
<p>	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););<br />
}</p>
<p>/* __put_lkb() is used when an lkb may not have an rsb attached to<br />
   it so we need to provide the lockspace explicitly */</p>
<p>static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	uint16_t bucket = (lkb->lkb_id >> 16);</p>
<p>	write_lock(&#038;ls->ls_lkbtbl[bucket].lock);<br />
	if (kref_put(&#038;lkb->lkb_ref, kill_lkb)) {<br />
		list_del(&#038;lkb->lkb_idtbl_list);<br />
		write_unlock(&#038;ls->ls_lkbtbl[bucket].lock);</p>
<p>		detach_lkb(lkb);</p>
<p>		/* for local/process lkbs, lvbptr points to caller&#8217;s lksb */<br />
		if (lkb->lkb_lvbptr &#038;&#038; is_master_copy(lkb))<br />
			dlm_free_lvb(lkb->lkb_lvbptr);<br />
		dlm_free_lkb(lkb);<br />
		return 1;<br />
	} else {<br />
		write_unlock(&#038;ls->ls_lkbtbl[bucket].lock);<br />
		return 0;<br />
	}<br />
}</p>
<p>int dlm_put_lkb(struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb););<br />
	DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb););</p>
<p>	ls = lkb->lkb_resource->res_ls;<br />
	return __put_lkb(ls, lkb);<br />
}</p>
<p>/* This is only called to add a reference when the code already holds<br />
   a valid reference to the lkb, so there&#8217;s no need for locking. */</p>
<p>static inline void hold_lkb(struct dlm_lkb *lkb)<br />
{<br />
	kref_get(&#038;lkb->lkb_ref);<br />
}</p>
<p>/* This is called when we need to remove a reference and are certain<br />
   it&#8217;s not the last ref.  e.g. del_lkb is always called between a<br />
   find_lkb/put_lkb and is always the inverse of a previous add_lkb.<br />
   put_lkb would work fine, but would involve unnecessary locking */</p>
<p>static inline void unhold_lkb(struct dlm_lkb *lkb)<br />
{<br />
	int rv;<br />
	rv = kref_put(&#038;lkb->lkb_ref, kill_lkb);<br />
	DLM_ASSERT(!rv, dlm_print_lkb(lkb););<br />
}</p>
<p>static void lkb_add_ordered(struct list_head *new, struct list_head *head,<br />
			    int mode)<br />
{<br />
	struct dlm_lkb *lkb = NULL;</p>
<p>	list_for_each_entry(lkb, head, lkb_statequeue)<br />
		if (lkb->lkb_rqmode < mode)<br />
			break;</p>
<p>	if (!lkb)<br />
		list_add_tail(new, head);<br />
	else<br />
		__list_add(new, lkb->lkb_statequeue.prev, &#038;lkb->lkb_statequeue);<br />
}</p>
<p>/* add/remove lkb to rsb&#8217;s grant/convert/wait queue */</p>
<p>static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)<br />
{<br />
	kref_get(&#038;lkb->lkb_ref);</p>
<p>	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););</p>
<p>	lkb->lkb_timestamp = ktime_get();</p>
<p>	lkb->lkb_status = status;</p>
<p>	switch (status) {<br />
	case DLM_LKSTS_WAITING:<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_HEADQUE)<br />
			list_add(&#038;lkb->lkb_statequeue, &#038;r->res_waitqueue);<br />
		else<br />
			list_add_tail(&#038;lkb->lkb_statequeue, &#038;r->res_waitqueue);<br />
		break;<br />
	case DLM_LKSTS_GRANTED:<br />
		/* convention says granted locks kept in order of grmode */<br />
		lkb_add_ordered(&#038;lkb->lkb_statequeue, &#038;r->res_grantqueue,<br />
				lkb->lkb_grmode);<br />
		break;<br />
	case DLM_LKSTS_CONVERT:<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_HEADQUE)<br />
			list_add(&#038;lkb->lkb_statequeue, &#038;r->res_convertqueue);<br />
		else<br />
			list_add_tail(&#038;lkb->lkb_statequeue,<br />
				      &#038;r->res_convertqueue);<br />
		break;<br />
	default:<br />
		DLM_ASSERT(0, dlm_print_lkb(lkb); printk(&raquo;sts=%d\n&raquo;, status););<br />
	}<br />
}</p>
<p>static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	lkb->lkb_status = 0;<br />
	list_del(&#038;lkb->lkb_statequeue);<br />
	unhold_lkb(lkb);<br />
}</p>
<p>static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)<br />
{<br />
	hold_lkb(lkb);<br />
	del_lkb(r, lkb);<br />
	add_lkb(r, lkb, sts);<br />
	unhold_lkb(lkb);<br />
}</p>
<p>static int msg_reply_type(int mstype)<br />
{<br />
	switch (mstype) {<br />
	case DLM_MSG_REQUEST:<br />
		return DLM_MSG_REQUEST_REPLY;<br />
	case DLM_MSG_CONVERT:<br />
		return DLM_MSG_CONVERT_REPLY;<br />
	case DLM_MSG_UNLOCK:<br />
		return DLM_MSG_UNLOCK_REPLY;<br />
	case DLM_MSG_CANCEL:<br />
		return DLM_MSG_CANCEL_REPLY;<br />
	case DLM_MSG_LOOKUP:<br />
		return DLM_MSG_LOOKUP_REPLY;<br />
	}<br />
	return -1;<br />
}</p>
<p>/* add/remove lkb from global waiters list of lkb&#8217;s waiting for<br />
   a reply from a remote node */</p>
<p>static int add_to_waiters(struct dlm_lkb *lkb, int mstype)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;<br />
	int error = 0;</p>
<p>	mutex_lock(&#038;ls->ls_waiters_mutex);</p>
<p>	if (is_overlap_unlock(lkb) ||<br />
	    (is_overlap_cancel(lkb) &#038;&#038; (mstype == DLM_MSG_CANCEL))) {<br />
		error = -EINVAL;<br />
		goto out;<br />
	}</p>
<p>	if (lkb->lkb_wait_type || is_overlap_cancel(lkb)) {<br />
		switch (mstype) {<br />
		case DLM_MSG_UNLOCK:<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;<br />
			break;<br />
		case DLM_MSG_CANCEL:<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;<br />
			break;<br />
		default:<br />
			error = -EBUSY;<br />
			goto out;<br />
		}<br />
		lkb->lkb_wait_count++;<br />
		hold_lkb(lkb);</p>
<p>		log_debug(ls, &laquo;addwait %x cur %d overlap %d count %d f %x&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_wait_type, mstype,<br />
			  lkb->lkb_wait_count, lkb->lkb_flags);<br />
		goto out;<br />
	}</p>
<p>	DLM_ASSERT(!lkb->lkb_wait_count,<br />
		   dlm_print_lkb(lkb);<br />
		   printk(&raquo;wait_count %d\n&raquo;, lkb->lkb_wait_count););</p>
<p>	lkb->lkb_wait_count++;<br />
	lkb->lkb_wait_type = mstype;<br />
	hold_lkb(lkb);<br />
	list_add(&#038;lkb->lkb_wait_reply, &#038;ls->ls_waiters);<br />
 out:<br />
	if (error)<br />
		log_error(ls, &laquo;addwait error %x %d flags %x %d %d %s&raquo;,<br />
			  lkb->lkb_id, error, lkb->lkb_flags, mstype,<br />
			  lkb->lkb_wait_type, lkb->lkb_resource->res_name);<br />
	mutex_unlock(&#038;ls->ls_waiters_mutex);<br />
	return error;<br />
}</p>
<p>/* We clear the RESEND flag because we might be taking an lkb off the waiters<br />
   list as part of process_requestqueue (e.g. a lookup that has an optimized<br />
   request reply on the requestqueue) between dlm_recover_waiters_pre() which<br />
   set RESEND and dlm_recover_waiters_post() */</p>
<p>static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,<br />
				struct dlm_message *ms)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;<br />
	int overlap_done = 0;</p>
<p>	if (is_overlap_unlock(lkb) &#038;&#038; (mstype == DLM_MSG_UNLOCK_REPLY)) {<br />
		log_debug(ls, &laquo;remwait %x unlock_reply overlap&raquo;, lkb->lkb_id);<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_UNLOCK;<br />
		overlap_done = 1;<br />
		goto out_del;<br />
	}</p>
<p>	if (is_overlap_cancel(lkb) &#038;&#038; (mstype == DLM_MSG_CANCEL_REPLY)) {<br />
		log_debug(ls, &laquo;remwait %x cancel_reply overlap&raquo;, lkb->lkb_id);<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		overlap_done = 1;<br />
		goto out_del;<br />
	}</p>
<p>	/* Cancel state was preemptively cleared by a successful convert,<br />
	   see next comment, nothing to do. */</p>
<p>	if ((mstype == DLM_MSG_CANCEL_REPLY) &#038;&#038;<br />
	    (lkb->lkb_wait_type != DLM_MSG_CANCEL)) {<br />
		log_debug(ls, &laquo;remwait %x cancel_reply wait_type %d&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_wait_type);<br />
		return -1;<br />
	}</p>
<p>	/* Remove for the convert reply, and premptively remove for the<br />
	   cancel reply.  A convert has been granted while there&#8217;s still<br />
	   an outstanding cancel on it (the cancel is moot and the result<br />
	   in the cancel reply should be 0).  We preempt the cancel reply<br />
	   because the app gets the convert result and then can follow up<br />
	   with another op, like convert.  This subsequent op would see the<br />
	   lingering state of the cancel and fail with -EBUSY. */</p>
<p>	if ((mstype == DLM_MSG_CONVERT_REPLY) &#038;&#038;<br />
	    (lkb->lkb_wait_type == DLM_MSG_CONVERT) &#038;&#038;<br />
	    is_overlap_cancel(lkb) &#038;&#038; ms &#038;&#038; !ms->m_result) {<br />
		log_debug(ls, &laquo;remwait %x convert_reply zap overlap_cancel&raquo;,<br />
			  lkb->lkb_id);<br />
		lkb->lkb_wait_type = 0;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		lkb->lkb_wait_count&#8211;;<br />
		goto out_del;<br />
	}</p>
<p>	/* N.B. type of reply may not always correspond to type of original<br />
	   msg due to lookup->request optimization, verify others? */</p>
<p>	if (lkb->lkb_wait_type) {<br />
		lkb->lkb_wait_type = 0;<br />
		goto out_del;<br />
	}</p>
<p>	log_error(ls, &laquo;remwait error %x reply %d flags %x no wait_type&raquo;,<br />
		  lkb->lkb_id, mstype, lkb->lkb_flags);<br />
	return -1;</p>
<p> out_del:<br />
	/* the force-unlock/cancel has completed and we haven&#8217;t recvd a reply<br />
	   to the op that was in progress prior to the unlock/cancel; we<br />
	   give up on any reply to the earlier op.  FIXME: not sure when/how<br />
	   this would happen */</p>
<p>	if (overlap_done &#038;&#038; lkb->lkb_wait_type) {<br />
		log_error(ls, &laquo;remwait error %x reply %d wait_type %d overlap&raquo;,<br />
			  lkb->lkb_id, mstype, lkb->lkb_wait_type);<br />
		lkb->lkb_wait_count&#8211;;<br />
		lkb->lkb_wait_type = 0;<br />
	}</p>
<p>	DLM_ASSERT(lkb->lkb_wait_count, dlm_print_lkb(lkb););</p>
<p>	lkb->lkb_flags &#038;= ~DLM_IFL_RESEND;<br />
	lkb->lkb_wait_count&#8211;;<br />
	if (!lkb->lkb_wait_count)<br />
		list_del_init(&#038;lkb->lkb_wait_reply);<br />
	unhold_lkb(lkb);<br />
	return 0;<br />
}</p>
<p>static int remove_from_waiters(struct dlm_lkb *lkb, int mstype)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;<br />
	int error;</p>
<p>	mutex_lock(&#038;ls->ls_waiters_mutex);<br />
	error = _remove_from_waiters(lkb, mstype, NULL);<br />
	mutex_unlock(&#038;ls->ls_waiters_mutex);<br />
	return error;<br />
}</p>
<p>/* Handles situations where we might be processing a &laquo;fake&raquo; or &laquo;stub&raquo; reply in<br />
   which we can&#8217;t try to take waiters_mutex again. */</p>
<p>static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;<br />
	int error;</p>
<p>	if (ms != &#038;ls->ls_stub_ms)<br />
		mutex_lock(&#038;ls->ls_waiters_mutex);<br />
	error = _remove_from_waiters(lkb, ms->m_type, ms);<br />
	if (ms != &#038;ls->ls_stub_ms)<br />
		mutex_unlock(&#038;ls->ls_waiters_mutex);<br />
	return error;<br />
}</p>
<p>static void dir_remove(struct dlm_rsb *r)<br />
{<br />
	int to_nodeid;</p>
<p>	if (dlm_no_directory(r->res_ls))<br />
		return;</p>
<p>	to_nodeid = dlm_dir_nodeid(r);<br />
	if (to_nodeid != dlm_our_nodeid())<br />
		send_remove(r);<br />
	else<br />
		dlm_dir_remove_entry(r->res_ls, to_nodeid,<br />
				     r->res_name, r->res_length);<br />
}</p>
<p>/* FIXME: shouldn&#8217;t this be able to exit as soon as one non-due rsb is<br />
   found since they are in order of newest to oldest? */</p>
<p>static int shrink_bucket(struct dlm_ls *ls, int b)<br />
{<br />
	struct dlm_rsb *r;<br />
	int count = 0, found;</p>
<p>	for (;;) {<br />
		found = 0;<br />
		spin_lock(&#038;ls->ls_rsbtbl[b].lock);<br />
		list_for_each_entry_reverse(r, &#038;ls->ls_rsbtbl[b].toss,<br />
					    res_hashchain) {<br />
			if (!time_after_eq(jiffies, r->res_toss_time +<br />
					   dlm_config.ci_toss_secs * HZ))<br />
				continue;<br />
			found = 1;<br />
			break;<br />
		}</p>
<p>		if (!found) {<br />
			spin_unlock(&#038;ls->ls_rsbtbl[b].lock);<br />
			break;<br />
		}</p>
<p>		if (kref_put(&#038;r->res_ref, kill_rsb)) {<br />
			list_del(&#038;r->res_hashchain);<br />
			spin_unlock(&#038;ls->ls_rsbtbl[b].lock);</p>
<p>			if (is_master(r))<br />
				dir_remove(r);<br />
			dlm_free_rsb(r);<br />
			count++;<br />
		} else {<br />
			spin_unlock(&#038;ls->ls_rsbtbl[b].lock);<br />
			log_error(ls, &laquo;tossed rsb in use %s&raquo;, r->res_name);<br />
		}<br />
	}</p>
<p>	return count;<br />
}</p>
<p>void dlm_scan_rsbs(struct dlm_ls *ls)<br />
{<br />
	int i;</p>
<p>	for (i = 0; i < ls->ls_rsbtbl_size; i++) {<br />
		shrink_bucket(ls, i);<br />
		if (dlm_locking_stopped(ls))<br />
			break;<br />
		cond_resched();<br />
	}<br />
}</p>
<p>static void add_timeout(struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;</p>
<p>	if (is_master_copy(lkb))<br />
		return;</p>
<p>	if (test_bit(LSFL_TIMEWARN, &#038;ls->ls_flags) &#038;&#038;<br />
	    !(lkb->lkb_exflags &#038; DLM_LKF_NODLCKWT)) {<br />
		lkb->lkb_flags |= DLM_IFL_WATCH_TIMEWARN;<br />
		goto add_it;<br />
	}<br />
	if (lkb->lkb_exflags &#038; DLM_LKF_TIMEOUT)<br />
		goto add_it;<br />
	return;</p>
<p> add_it:<br />
	DLM_ASSERT(list_empty(&#038;lkb->lkb_time_list), dlm_print_lkb(lkb););<br />
	mutex_lock(&#038;ls->ls_timeout_mutex);<br />
	hold_lkb(lkb);<br />
	list_add_tail(&#038;lkb->lkb_time_list, &#038;ls->ls_timeout);<br />
	mutex_unlock(&#038;ls->ls_timeout_mutex);<br />
}</p>
<p>static void del_timeout(struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;</p>
<p>	mutex_lock(&#038;ls->ls_timeout_mutex);<br />
	if (!list_empty(&#038;lkb->lkb_time_list)) {<br />
		list_del_init(&#038;lkb->lkb_time_list);<br />
		unhold_lkb(lkb);<br />
	}<br />
	mutex_unlock(&#038;ls->ls_timeout_mutex);<br />
}</p>
<p>/* FIXME: is it safe to look at lkb_exflags, lkb_flags, lkb_timestamp, and<br />
   lkb_lksb_timeout without lock_rsb?  Note: we can&#8217;t lock timeout_mutex<br />
   and then lock rsb because of lock ordering in add_timeout.  We may need<br />
   to specify some special timeout-related bits in the lkb that are just to<br />
   be accessed under the timeout_mutex. */</p>
<p>void dlm_scan_timeout(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	struct dlm_lkb *lkb;<br />
	int do_cancel, do_warn;<br />
	s64 wait_us;</p>
<p>	for (;;) {<br />
		if (dlm_locking_stopped(ls))<br />
			break;</p>
<p>		do_cancel = 0;<br />
		do_warn = 0;<br />
		mutex_lock(&#038;ls->ls_timeout_mutex);<br />
		list_for_each_entry(lkb, &#038;ls->ls_timeout, lkb_time_list) {</p>
<p>			wait_us = ktime_to_us(ktime_sub(ktime_get(),<br />
					      		lkb->lkb_timestamp));</p>
<p>			if ((lkb->lkb_exflags &#038; DLM_LKF_TIMEOUT) &#038;&#038;<br />
			    wait_us >= (lkb->lkb_timeout_cs * 10000))<br />
				do_cancel = 1;</p>
<p>			if ((lkb->lkb_flags &#038; DLM_IFL_WATCH_TIMEWARN) &#038;&#038;<br />
			    wait_us >= dlm_config.ci_timewarn_cs * 10000)<br />
				do_warn = 1;</p>
<p>			if (!do_cancel &#038;&#038; !do_warn)<br />
				continue;<br />
			hold_lkb(lkb);<br />
			break;<br />
		}<br />
		mutex_unlock(&#038;ls->ls_timeout_mutex);</p>
<p>		if (!do_cancel &#038;&#038; !do_warn)<br />
			break;</p>
<p>		r = lkb->lkb_resource;<br />
		hold_rsb(r);<br />
		lock_rsb(r);</p>
<p>		if (do_warn) {<br />
			/* clear flag so we only warn once */<br />
			lkb->lkb_flags &#038;= ~DLM_IFL_WATCH_TIMEWARN;<br />
			if (!(lkb->lkb_exflags &#038; DLM_LKF_TIMEOUT))<br />
				del_timeout(lkb);<br />
			dlm_timeout_warn(lkb);<br />
		}</p>
<p>		if (do_cancel) {<br />
			log_debug(ls, &laquo;timeout cancel %x node %d %s&raquo;,<br />
				  lkb->lkb_id, lkb->lkb_nodeid, r->res_name);<br />
			lkb->lkb_flags &#038;= ~DLM_IFL_WATCH_TIMEWARN;<br />
			lkb->lkb_flags |= DLM_IFL_TIMEOUT_CANCEL;<br />
			del_timeout(lkb);<br />
			_cancel_lock(r, lkb);<br />
		}</p>
<p>		unlock_rsb(r);<br />
		unhold_rsb(r);<br />
		dlm_put_lkb(lkb);<br />
	}<br />
}</p>
<p>/* This is only called by dlm_recoverd, and we rely on dlm_ls_stop() stopping<br />
   dlm_recoverd before checking/setting ls_recover_begin. */</p>
<p>void dlm_adjust_timeouts(struct dlm_ls *ls)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	u64 adj_us = jiffies_to_usecs(jiffies &#8211; ls->ls_recover_begin);</p>
<p>	ls->ls_recover_begin = 0;<br />
	mutex_lock(&#038;ls->ls_timeout_mutex);<br />
	list_for_each_entry(lkb, &#038;ls->ls_timeout, lkb_time_list)<br />
		lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us);<br />
	mutex_unlock(&#038;ls->ls_timeout_mutex);<br />
}</p>
<p>/* lkb is master or local copy */</p>
<p>static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int b, len = r->res_ls->ls_lvblen;</p>
<p>	/* b=1 lvb returned to caller<br />
	   b=0 lvb written to rsb or invalidated<br />
	   b=-1 do nothing */</p>
<p>	b =  dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];</p>
<p>	if (b == 1) {<br />
		if (!lkb->lkb_lvbptr)<br />
			return;</p>
<p>		if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
			return;</p>
<p>		if (!r->res_lvbptr)<br />
			return;</p>
<p>		memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);<br />
		lkb->lkb_lvbseq = r->res_lvbseq;</p>
<p>	} else if (b == 0) {<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_IVVALBLK) {<br />
			rsb_set_flag(r, RSB_VALNOTVALID);<br />
			return;<br />
		}</p>
<p>		if (!lkb->lkb_lvbptr)<br />
			return;</p>
<p>		if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
			return;</p>
<p>		if (!r->res_lvbptr)<br />
			r->res_lvbptr = dlm_allocate_lvb(r->res_ls);</p>
<p>		if (!r->res_lvbptr)<br />
			return;</p>
<p>		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);<br />
		r->res_lvbseq++;<br />
		lkb->lkb_lvbseq = r->res_lvbseq;<br />
		rsb_clear_flag(r, RSB_VALNOTVALID);<br />
	}</p>
<p>	if (rsb_flag(r, RSB_VALNOTVALID))<br />
		lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID;<br />
}</p>
<p>static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	if (lkb->lkb_grmode < DLM_LOCK_PW)<br />
		return;</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_IVVALBLK) {<br />
		rsb_set_flag(r, RSB_VALNOTVALID);<br />
		return;<br />
	}</p>
<p>	if (!lkb->lkb_lvbptr)<br />
		return;</p>
<p>	if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
		return;</p>
<p>	if (!r->res_lvbptr)<br />
		r->res_lvbptr = dlm_allocate_lvb(r->res_ls);</p>
<p>	if (!r->res_lvbptr)<br />
		return;</p>
<p>	memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);<br />
	r->res_lvbseq++;<br />
	rsb_clear_flag(r, RSB_VALNOTVALID);<br />
}</p>
<p>/* lkb is process copy (pc) */</p>
<p>static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
			    struct dlm_message *ms)<br />
{<br />
	int b;</p>
<p>	if (!lkb->lkb_lvbptr)<br />
		return;</p>
<p>	if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
		return;</p>
<p>	b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];<br />
	if (b == 1) {<br />
		int len = receive_extralen(ms);<br />
		if (len > DLM_RESNAME_MAXLEN)<br />
			len = DLM_RESNAME_MAXLEN;<br />
		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);<br />
		lkb->lkb_lvbseq = ms->m_lvbseq;<br />
	}<br />
}</p>
<p>/* Manipulate lkb&#8217;s on rsb&#8217;s convert/granted/waiting queues<br />
   remove_lock &#8212; used for unlock, removes lkb from granted<br />
   revert_lock &#8212; used for cancel, moves lkb from convert to granted<br />
   grant_lock  &#8212; used for request and convert, adds lkb to granted or<br />
                  moves lkb from convert or waiting to granted</p>
<p>   Each of these is used for master or local copy lkb&#8217;s.  There is<br />
   also a _pc() variation used to make the corresponding change on<br />
   a process copy (pc) lkb. */</p>
<p>static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	del_lkb(r, lkb);<br />
	lkb->lkb_grmode = DLM_LOCK_IV;<br />
	/* this unhold undoes the original ref from create_lkb()<br />
	   so this leads to the lkb being freed */<br />
	unhold_lkb(lkb);<br />
}</p>
<p>static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	set_lvb_unlock(r, lkb);<br />
	_remove_lock(r, lkb);<br />
}</p>
<p>static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	_remove_lock(r, lkb);<br />
}</p>
<p>/* returns: 0 did nothing<br />
	    1 moved lock to granted<br />
	   -1 removed lock */</p>
<p>static int revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int rv = 0;</p>
<p>	lkb->lkb_rqmode = DLM_LOCK_IV;</p>
<p>	switch (lkb->lkb_status) {<br />
	case DLM_LKSTS_GRANTED:<br />
		break;<br />
	case DLM_LKSTS_CONVERT:<br />
		move_lkb(r, lkb, DLM_LKSTS_GRANTED);<br />
		rv = 1;<br />
		break;<br />
	case DLM_LKSTS_WAITING:<br />
		del_lkb(r, lkb);<br />
		lkb->lkb_grmode = DLM_LOCK_IV;<br />
		/* this unhold undoes the original ref from create_lkb()<br />
		   so this leads to the lkb being freed */<br />
		unhold_lkb(lkb);<br />
		rv = -1;<br />
		break;<br />
	default:<br />
		log_print(&raquo;invalid status for revert %d&raquo;, lkb->lkb_status);<br />
	}<br />
	return rv;<br />
}</p>
<p>static int revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	return revert_lock(r, lkb);<br />
}</p>
<p>static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	if (lkb->lkb_grmode != lkb->lkb_rqmode) {<br />
		lkb->lkb_grmode = lkb->lkb_rqmode;<br />
		if (lkb->lkb_status)<br />
			move_lkb(r, lkb, DLM_LKSTS_GRANTED);<br />
		else<br />
			add_lkb(r, lkb, DLM_LKSTS_GRANTED);<br />
	}</p>
<p>	lkb->lkb_rqmode = DLM_LOCK_IV;<br />
}</p>
<p>static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	set_lvb_lock(r, lkb);<br />
	_grant_lock(r, lkb);<br />
	lkb->lkb_highbast = 0;<br />
}</p>
<p>static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
			  struct dlm_message *ms)<br />
{<br />
	set_lvb_lock_pc(r, lkb, ms);<br />
	_grant_lock(r, lkb);<br />
}</p>
<p>/* called by grant_pending_locks() which means an async grant message must<br />
   be sent to the requesting node in addition to granting the lock if the<br />
   lkb belongs to a remote node. */</p>
<p>static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	grant_lock(r, lkb);<br />
	if (is_master_copy(lkb))<br />
		send_grant(r, lkb);<br />
	else<br />
		queue_cast(r, lkb, 0);<br />
}</p>
<p>/* The special CONVDEADLK, ALTPR and ALTCW flags allow the master to<br />
   change the granted/requested modes.  We&#8217;re munging things accordingly in<br />
   the process copy.<br />
   CONVDEADLK: our grmode may have been forced down to NL to resolve a<br />
   conversion deadlock<br />
   ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become<br />
   compatible with other granted locks */</p>
<p>static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	if (ms->m_type != DLM_MSG_CONVERT_REPLY) {<br />
		log_print(&raquo;munge_demoted %x invalid reply type %d&raquo;,<br />
			  lkb->lkb_id, ms->m_type);<br />
		return;<br />
	}</p>
<p>	if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {<br />
		log_print(&raquo;munge_demoted %x invalid modes gr %d rq %d&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);<br />
		return;<br />
	}</p>
<p>	lkb->lkb_grmode = DLM_LOCK_NL;<br />
}</p>
<p>static void munge_altmode(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	if (ms->m_type != DLM_MSG_REQUEST_REPLY &#038;&#038;<br />
	    ms->m_type != DLM_MSG_GRANT) {<br />
		log_print(&raquo;munge_altmode %x invalid reply type %d&raquo;,<br />
			  lkb->lkb_id, ms->m_type);<br />
		return;<br />
	}</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_ALTPR)<br />
		lkb->lkb_rqmode = DLM_LOCK_PR;<br />
	else if (lkb->lkb_exflags &#038; DLM_LKF_ALTCW)<br />
		lkb->lkb_rqmode = DLM_LOCK_CW;<br />
	else {<br />
		log_print(&raquo;munge_altmode invalid exflags %x&raquo;, lkb->lkb_exflags);<br />
		dlm_print_lkb(lkb);<br />
	}<br />
}</p>
<p>static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)<br />
{<br />
	struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,<br />
					   lkb_statequeue);<br />
	if (lkb->lkb_id == first->lkb_id)<br />
		return 1;</p>
<p>	return 0;<br />
}</p>
<p>/* Check if the given lkb conflicts with another lkb on the queue. */</p>
<p>static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_lkb *this;</p>
<p>	list_for_each_entry(this, head, lkb_statequeue) {<br />
		if (this == lkb)<br />
			continue;<br />
		if (!modes_compat(this, lkb))<br />
			return 1;<br />
	}<br />
	return 0;<br />
}</p>
<p>/*<br />
 * &laquo;A conversion deadlock arises with a pair of lock requests in the converting<br />
 * queue for one resource.  The granted mode of each lock blocks the requested<br />
 * mode of the other lock.&raquo;<br />
 *<br />
 * Part 2: if the granted mode of lkb is preventing an earlier lkb in the<br />
 * convert queue from being granted, then deadlk/demote lkb.<br />
 *<br />
 * Example:<br />
 * Granted Queue: empty<br />
 * Convert Queue: NL->EX (first lock)<br />
 *                PR->EX (second lock)<br />
 *<br />
 * The first lock can&#8217;t be granted because of the granted mode of the second<br />
 * lock and the second lock can&#8217;t be granted because it&#8217;s not first in the<br />
 * list.  We either cancel lkb&#8217;s conversion (PR->EX) and return EDEADLK, or we<br />
 * demote the granted mode of lkb (from PR to NL) if it has the CONVDEADLK<br />
 * flag set and return DEMOTED in the lksb flags.<br />
 *<br />
 * Originally, this function detected conv-deadlk in a more limited scope:<br />
 * &#8211; if !modes_compat(lkb1, lkb2) &#038;&#038; !modes_compat(lkb2, lkb1), or<br />
 * &#8211; if lkb1 was the first entry in the queue (not just earlier), and was<br />
 *   blocked by the granted mode of lkb2, and there was nothing on the<br />
 *   granted queue preventing lkb1 from being granted immediately, i.e.<br />
 *   lkb2 was the only thing preventing lkb1 from being granted.<br />
 *<br />
 * That second condition meant we&#8217;d only say there was conv-deadlk if<br />
 * resolving it (by demotion) would lead to the first lock on the convert<br />
 * queue being granted right away.  It allowed conversion deadlocks to exist<br />
 * between locks on the convert queue while they couldn&#8217;t be granted anyway.<br />
 *<br />
 * Now, we detect and take action on conversion deadlocks immediately when<br />
 * they&#8217;re created, even if they may not be immediately consequential.  If<br />
 * lkb1 exists anywhere in the convert queue and lkb2 comes in with a granted<br />
 * mode that would prevent lkb1&#8217;s conversion from being granted, we do a<br />
 * deadlk/demote on lkb2 right away and don&#8217;t let it onto the convert queue.<br />
 * I think this means that the lkb_is_ahead condition below should always<br />
 * be zero, i.e. there will never be conv-deadlk between two locks that are<br />
 * both already on the convert queue.<br />
 */</p>
<p>static int conversion_deadlock_detect(struct dlm_rsb *r, struct dlm_lkb *lkb2)<br />
{<br />
	struct dlm_lkb *lkb1;<br />
	int lkb_is_ahead = 0;</p>
<p>	list_for_each_entry(lkb1, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		if (lkb1 == lkb2) {<br />
			lkb_is_ahead = 1;<br />
			continue;<br />
		}</p>
<p>		if (!lkb_is_ahead) {<br />
			if (!modes_compat(lkb2, lkb1))<br />
				return 1;<br />
		} else {<br />
			if (!modes_compat(lkb2, lkb1) &#038;&#038;<br />
			    !modes_compat(lkb1, lkb2))<br />
				return 1;<br />
		}<br />
	}<br />
	return 0;<br />
}</p>
<p>/*<br />
 * Return 1 if the lock can be granted, 0 otherwise.<br />
 * Also detect and resolve conversion deadlocks.<br />
 *<br />
 * lkb is the lock to be granted<br />
 *<br />
 * now is 1 if the function is being called in the context of the<br />
 * immediate request, it is 0 if called later, after the lock has been<br />
 * queued.<br />
 *<br />
 * References are from chapter 6 of &laquo;VAXcluster Principles&raquo; by Roy Davis<br />
 */</p>
<p>static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)<br />
{<br />
	int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);</p>
<p>	/*<br />
	 * 6-10: Version 5.4 introduced an option to address the phenomenon of<br />
	 * a new request for a NL mode lock being blocked.<br />
	 *<br />
	 * 6-11: If the optional EXPEDITE flag is used with the new NL mode<br />
	 * request, then it would be granted.  In essence, the use of this flag<br />
	 * tells the Lock Manager to expedite theis request by not considering<br />
	 * what may be in the CONVERTING or WAITING queues&#8230;  As of this<br />
	 * writing, the EXPEDITE flag can be used only with new requests for NL<br />
	 * mode locks.  This flag is not valid for conversion requests.<br />
	 *<br />
	 * A shortcut.  Earlier checks return an error if EXPEDITE is used in a<br />
	 * conversion or used with a non-NL requested mode.  We also know an<br />
	 * EXPEDITE request is always granted immediately, so now must always<br />
	 * be 1.  The full condition to grant an expedite request: (now &#038;&#038;<br />
	 * !conv &#038;&#038; lkb->rqmode == DLM_LOCK_NL &#038;&#038; (flags &#038; EXPEDITE)) can<br />
	 * therefore be shortened to just checking the flag.<br />
	 */</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_EXPEDITE)<br />
		return 1;</p>
<p>	/*<br />
	 * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be<br />
	 * added to the remaining conditions.<br />
	 */</p>
<p>	if (queue_conflict(&#038;r->res_grantqueue, lkb))<br />
		goto out;</p>
<p>	/*<br />
	 * 6-3: By default, a conversion request is immediately granted if the<br />
	 * requested mode is compatible with the modes of all other granted<br />
	 * locks<br />
	 */</p>
<p>	if (queue_conflict(&#038;r->res_convertqueue, lkb))<br />
		goto out;</p>
<p>	/*<br />
	 * 6-5: But the default algorithm for deciding whether to grant or<br />
	 * queue conversion requests does not by itself guarantee that such<br />
	 * requests are serviced on a &laquo;first come first serve&raquo; basis.  This, in<br />
	 * turn, can lead to a phenomenon known as &laquo;indefinate postponement&raquo;.<br />
	 *<br />
	 * 6-7: This issue is dealt with by using the optional QUECVT flag with<br />
	 * the system service employed to request a lock conversion.  This flag<br />
	 * forces certain conversion requests to be queued, even if they are<br />
	 * compatible with the granted modes of other locks on the same<br />
	 * resource.  Thus, the use of this flag results in conversion requests<br />
	 * being ordered on a &laquo;first come first servce&raquo; basis.<br />
	 *<br />
	 * DCT: This condition is all about new conversions being able to occur<br />
	 * &laquo;in place&raquo; while the lock remains on the granted queue (assuming<br />
	 * nothing else conflicts.)  IOW if QUECVT isn&#8217;t set, a conversion<br />
	 * doesn&#8217;t _have_ to go onto the convert queue where it&#8217;s processed in<br />
	 * order.  The &laquo;now&raquo; variable is necessary to distinguish converts<br />
	 * being received and processed for the first time now, because once a<br />
	 * convert is moved to the conversion queue the condition below applies<br />
	 * requiring fifo granting.<br />
	 */</p>
<p>	if (now &#038;&#038; conv &#038;&#038; !(lkb->lkb_exflags &#038; DLM_LKF_QUECVT))<br />
		return 1;</p>
<p>	/*<br />
	 * The NOORDER flag is set to avoid the standard vms rules on grant<br />
	 * order.<br />
	 */</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_NOORDER)<br />
		return 1;</p>
<p>	/*<br />
	 * 6-3: Once in that queue [CONVERTING], a conversion request cannot be<br />
	 * granted until all other conversion requests ahead of it are granted<br />
	 * and/or canceled.<br />
	 */</p>
<p>	if (!now &#038;&#038; conv &#038;&#038; first_in_list(lkb, &#038;r->res_convertqueue))<br />
		return 1;</p>
<p>	/*<br />
	 * 6-4: By default, a new request is immediately granted only if all<br />
	 * three of the following conditions are satisfied when the request is<br />
	 * issued:<br />
	 * &#8211; The queue of ungranted conversion requests for the resource is<br />
	 *   empty.<br />
	 * &#8211; The queue of ungranted new requests for the resource is empty.<br />
	 * &#8211; The mode of the new request is compatible with the most<br />
	 *   restrictive mode of all granted locks on the resource.<br />
	 */</p>
<p>	if (now &#038;&#038; !conv &#038;&#038; list_empty(&#038;r->res_convertqueue) &#038;&#038;<br />
	    list_empty(&#038;r->res_waitqueue))<br />
		return 1;</p>
<p>	/*<br />
	 * 6-4: Once a lock request is in the queue of ungranted new requests,<br />
	 * it cannot be granted until the queue of ungranted conversion<br />
	 * requests is empty, all ungranted new requests ahead of it are<br />
	 * granted and/or canceled, and it is compatible with the granted mode<br />
	 * of the most restrictive lock granted on the resource.<br />
	 */</p>
<p>	if (!now &#038;&#038; !conv &#038;&#038; list_empty(&#038;r->res_convertqueue) &#038;&#038;<br />
	    first_in_list(lkb, &#038;r->res_waitqueue))<br />
		return 1;<br />
 out:<br />
	return 0;<br />
}</p>
<p>static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,<br />
			  int *err)<br />
{<br />
	int rv;<br />
	int8_t alt = 0, rqmode = lkb->lkb_rqmode;<br />
	int8_t is_convert = (lkb->lkb_grmode != DLM_LOCK_IV);</p>
<p>	if (err)<br />
		*err = 0;</p>
<p>	rv = _can_be_granted(r, lkb, now);<br />
	if (rv)<br />
		goto out;</p>
<p>	/*<br />
	 * The CONVDEADLK flag is non-standard and tells the dlm to resolve<br />
	 * conversion deadlocks by demoting grmode to NL, otherwise the dlm<br />
	 * cancels one of the locks.<br />
	 */</p>
<p>	if (is_convert &#038;&#038; can_be_queued(lkb) &#038;&#038;<br />
	    conversion_deadlock_detect(r, lkb)) {<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_CONVDEADLK) {<br />
			lkb->lkb_grmode = DLM_LOCK_NL;<br />
			lkb->lkb_sbflags |= DLM_SBF_DEMOTED;<br />
		} else if (!(lkb->lkb_exflags &#038; DLM_LKF_NODLCKWT)) {<br />
			if (err)<br />
				*err = -EDEADLK;<br />
			else {<br />
				log_print(&raquo;can_be_granted deadlock %x now %d&raquo;,<br />
					  lkb->lkb_id, now);<br />
				dlm_dump_rsb(r);<br />
			}<br />
		}<br />
		goto out;<br />
	}</p>
<p>	/*<br />
	 * The ALTPR and ALTCW flags are non-standard and tell the dlm to try<br />
	 * to grant a request in a mode other than the normal rqmode.  It&#8217;s a<br />
	 * simple way to provide a big optimization to applications that can<br />
	 * use them.<br />
	 */</p>
<p>	if (rqmode != DLM_LOCK_PR &#038;&#038; (lkb->lkb_exflags &#038; DLM_LKF_ALTPR))<br />
		alt = DLM_LOCK_PR;<br />
	else if (rqmode != DLM_LOCK_CW &#038;&#038; (lkb->lkb_exflags &#038; DLM_LKF_ALTCW))<br />
		alt = DLM_LOCK_CW;</p>
<p>	if (alt) {<br />
		lkb->lkb_rqmode = alt;<br />
		rv = _can_be_granted(r, lkb, now);<br />
		if (rv)<br />
			lkb->lkb_sbflags |= DLM_SBF_ALTMODE;<br />
		else<br />
			lkb->lkb_rqmode = rqmode;<br />
	}<br />
 out:<br />
	return rv;<br />
}</p>
<p>/* FIXME: I don&#8217;t think that can_be_granted() can/will demote or find deadlock<br />
   for locks pending on the convert list.  Once verified (watch for these<br />
   log_prints), we should be able to just call _can_be_granted() and not<br />
   bother with the demote/deadlk cases here (and there&#8217;s no easy way to deal<br />
   with a deadlk here, we&#8217;d have to generate something like grant_lock with<br />
   the deadlk error.) */</p>
<p>/* Returns the highest requested mode of all blocked conversions; sets<br />
   cw if there&#8217;s a blocked conversion to DLM_LOCK_CW. */</p>
<p>static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw)<br />
{<br />
	struct dlm_lkb *lkb, *s;<br />
	int hi, demoted, quit, grant_restart, demote_restart;<br />
	int deadlk;</p>
<p>	quit = 0;<br />
 restart:<br />
	grant_restart = 0;<br />
	demote_restart = 0;<br />
	hi = DLM_LOCK_IV;</p>
<p>	list_for_each_entry_safe(lkb, s, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		demoted = is_demoted(lkb);<br />
		deadlk = 0;</p>
<p>		if (can_be_granted(r, lkb, 0, &#038;deadlk)) {<br />
			grant_lock_pending(r, lkb);<br />
			grant_restart = 1;<br />
			continue;<br />
		}</p>
<p>		if (!demoted &#038;&#038; is_demoted(lkb)) {<br />
			log_print(&raquo;WARN: pending demoted %x node %d %s&raquo;,<br />
				  lkb->lkb_id, lkb->lkb_nodeid, r->res_name);<br />
			demote_restart = 1;<br />
			continue;<br />
		}</p>
<p>		if (deadlk) {<br />
			log_print(&raquo;WARN: pending deadlock %x node %d %s&raquo;,<br />
				  lkb->lkb_id, lkb->lkb_nodeid, r->res_name);<br />
			dlm_dump_rsb(r);<br />
			continue;<br />
		}</p>
<p>		hi = max_t(int, lkb->lkb_rqmode, hi);</p>
<p>		if (cw &#038;&#038; lkb->lkb_rqmode == DLM_LOCK_CW)<br />
			*cw = 1;<br />
	}</p>
<p>	if (grant_restart)<br />
		goto restart;<br />
	if (demote_restart &#038;&#038; !quit) {<br />
		quit = 1;<br />
		goto restart;<br />
	}</p>
<p>	return max_t(int, high, hi);<br />
}</p>
<p>static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw)<br />
{<br />
	struct dlm_lkb *lkb, *s;</p>
<p>	list_for_each_entry_safe(lkb, s, &#038;r->res_waitqueue, lkb_statequeue) {<br />
		if (can_be_granted(r, lkb, 0, NULL))<br />
			grant_lock_pending(r, lkb);<br />
                else {<br />
			high = max_t(int, lkb->lkb_rqmode, high);<br />
			if (lkb->lkb_rqmode == DLM_LOCK_CW)<br />
				*cw = 1;<br />
		}<br />
	}</p>
<p>	return high;<br />
}</p>
<p>/* cw of 1 means there&#8217;s a lock with a rqmode of DLM_LOCK_CW that&#8217;s blocked<br />
   on either the convert or waiting queue.<br />
   high is the largest rqmode of all locks blocked on the convert or<br />
   waiting queue. */</p>
<p>static int lock_requires_bast(struct dlm_lkb *gr, int high, int cw)<br />
{<br />
	if (gr->lkb_grmode == DLM_LOCK_PR &#038;&#038; cw) {<br />
		if (gr->lkb_highbast < DLM_LOCK_EX)<br />
			return 1;<br />
		return 0;<br />
	}</p>
<p>	if (gr->lkb_highbast < high &#038;&#038;<br />
	    !__dlm_compat_matrix[gr->lkb_grmode+1][high+1])<br />
		return 1;<br />
	return 0;<br />
}</p>
<p>static void grant_pending_locks(struct dlm_rsb *r)<br />
{<br />
	struct dlm_lkb *lkb, *s;<br />
	int high = DLM_LOCK_IV;<br />
	int cw = 0;</p>
<p>	DLM_ASSERT(is_master(r), dlm_dump_rsb(r););</p>
<p>	high = grant_pending_convert(r, high, &#038;cw);<br />
	high = grant_pending_wait(r, high, &#038;cw);</p>
<p>	if (high == DLM_LOCK_IV)<br />
		return;</p>
<p>	/*<br />
	 * If there are locks left on the wait/convert queue then send blocking<br />
	 * ASTs to granted locks based on the largest requested mode (high)<br />
	 * found above.<br />
	 */</p>
<p>	list_for_each_entry_safe(lkb, s, &#038;r->res_grantqueue, lkb_statequeue) {<br />
		if (lkb->lkb_bastfn &#038;&#038; lock_requires_bast(lkb, high, cw)) {<br />
			if (cw &#038;&#038; high == DLM_LOCK_PR &#038;&#038;<br />
			    lkb->lkb_grmode == DLM_LOCK_PR)<br />
				queue_bast(r, lkb, DLM_LOCK_CW);<br />
			else<br />
				queue_bast(r, lkb, high);<br />
			lkb->lkb_highbast = high;<br />
		}<br />
	}<br />
}</p>
<p>static int modes_require_bast(struct dlm_lkb *gr, struct dlm_lkb *rq)<br />
{<br />
	if ((gr->lkb_grmode == DLM_LOCK_PR &#038;&#038; rq->lkb_rqmode == DLM_LOCK_CW) ||<br />
	    (gr->lkb_grmode == DLM_LOCK_CW &#038;&#038; rq->lkb_rqmode == DLM_LOCK_PR)) {<br />
		if (gr->lkb_highbast < DLM_LOCK_EX)<br />
			return 1;<br />
		return 0;<br />
	}</p>
<p>	if (gr->lkb_highbast < rq->lkb_rqmode &#038;&#038; !modes_compat(gr, rq))<br />
		return 1;<br />
	return 0;<br />
}</p>
<p>static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,<br />
			    struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_lkb *gr;</p>
<p>	list_for_each_entry(gr, head, lkb_statequeue) {<br />
		if (gr->lkb_bastfn &#038;&#038; modes_require_bast(gr, lkb)) {<br />
			queue_bast(r, gr, lkb->lkb_rqmode);<br />
			gr->lkb_highbast = lkb->lkb_rqmode;<br />
		}<br />
	}<br />
}</p>
<p>static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	send_bast_queue(r, &#038;r->res_grantqueue, lkb);<br />
}</p>
<p>static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	send_bast_queue(r, &#038;r->res_grantqueue, lkb);<br />
	send_bast_queue(r, &#038;r->res_convertqueue, lkb);<br />
}</p>
<p>/* set_master(r, lkb) &#8212; set the master nodeid of a resource</p>
<p>   The purpose of this function is to set the nodeid field in the given<br />
   lkb using the nodeid field in the given rsb.  If the rsb&#8217;s nodeid is<br />
   known, it can just be copied to the lkb and the function will return<br />
   0.  If the rsb&#8217;s nodeid is _not_ known, it needs to be looked up<br />
   before it can be copied to the lkb.</p>
<p>   When the rsb nodeid is being looked up remotely, the initial lkb<br />
   causing the lookup is kept on the ls_waiters list waiting for the<br />
   lookup reply.  Other lkb&#8217;s waiting for the same rsb lookup are kept<br />
   on the rsb&#8217;s res_lookup list until the master is verified.</p>
<p>   Return values:<br />
   0: nodeid is set in rsb/lkb and the caller should go ahead and use it<br />
   1: the rsb master is not available and the lkb has been placed on<br />
      a wait queue<br />
*/</p>
<p>static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_ls *ls = r->res_ls;<br />
	int i, error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();</p>
<p>	if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {<br />
		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);<br />
		r->res_first_lkid = lkb->lkb_id;<br />
		lkb->lkb_nodeid = r->res_nodeid;<br />
		return 0;<br />
	}</p>
<p>	if (r->res_first_lkid &#038;&#038; r->res_first_lkid != lkb->lkb_id) {<br />
		list_add_tail(&#038;lkb->lkb_rsb_lookup, &#038;r->res_lookup);<br />
		return 1;<br />
	}</p>
<p>	if (r->res_nodeid == 0) {<br />
		lkb->lkb_nodeid = 0;<br />
		return 0;<br />
	}</p>
<p>	if (r->res_nodeid > 0) {<br />
		lkb->lkb_nodeid = r->res_nodeid;<br />
		return 0;<br />
	}</p>
<p>	DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r););</p>
<p>	dir_nodeid = dlm_dir_nodeid(r);</p>
<p>	if (dir_nodeid != our_nodeid) {<br />
		r->res_first_lkid = lkb->lkb_id;<br />
		send_lookup(r, lkb);<br />
		return 1;<br />
	}</p>
<p>	for (i = 0; i < 2; i++) {<br />
		/* It's possible for dlm_scand to remove an old rsb for<br />
		   this same resource from the toss list, us to create<br />
		   a new one, look up the master locally, and find it<br />
		   already exists just before dlm_scand does the<br />
		   dir_remove() on the previous rsb. */</p>
<p>		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,<br />
				       r->res_length, &#038;ret_nodeid);<br />
		if (!error)<br />
			break;<br />
		log_debug(ls, &laquo;dir_lookup error %d %s&raquo;, error, r->res_name);<br />
		schedule();<br />
	}<br />
	if (error &#038;&#038; error != -EEXIST)<br />
		return error;</p>
<p>	if (ret_nodeid == our_nodeid) {<br />
		r->res_first_lkid = 0;<br />
		r->res_nodeid = 0;<br />
		lkb->lkb_nodeid = 0;<br />
	} else {<br />
		r->res_first_lkid = lkb->lkb_id;<br />
		r->res_nodeid = ret_nodeid;<br />
		lkb->lkb_nodeid = ret_nodeid;<br />
	}<br />
	return 0;<br />
}</p>
<p>static void process_lookup_list(struct dlm_rsb *r)<br />
{<br />
	struct dlm_lkb *lkb, *safe;</p>
<p>	list_for_each_entry_safe(lkb, safe, &#038;r->res_lookup, lkb_rsb_lookup) {<br />
		list_del_init(&#038;lkb->lkb_rsb_lookup);<br />
		_request_lock(r, lkb);<br />
		schedule();<br />
	}<br />
}</p>
<p>/* confirm_master &#8212; confirm (or deny) an rsb&#8217;s master nodeid */</p>
<p>static void confirm_master(struct dlm_rsb *r, int error)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	if (!r->res_first_lkid)<br />
		return;</p>
<p>	switch (error) {<br />
	case 0:<br />
	case -EINPROGRESS:<br />
		r->res_first_lkid = 0;<br />
		process_lookup_list(r);<br />
		break;</p>
<p>	case -EAGAIN:<br />
	case -EBADR:<br />
	case -ENOTBLK:<br />
		/* the remote request failed and won&#8217;t be retried (it was<br />
		   a NOQUEUE, or has been canceled/unlocked); make a waiting<br />
		   lkb the first_lkid */</p>
<p>		r->res_first_lkid = 0;</p>
<p>		if (!list_empty(&#038;r->res_lookup)) {<br />
			lkb = list_entry(r->res_lookup.next, struct dlm_lkb,<br />
					 lkb_rsb_lookup);<br />
			list_del_init(&#038;lkb->lkb_rsb_lookup);<br />
			r->res_first_lkid = lkb->lkb_id;<br />
			_request_lock(r, lkb);<br />
		}<br />
		break;</p>
<p>	default:<br />
		log_error(r->res_ls, &laquo;confirm_master unknown error %d&raquo;, error);<br />
	}<br />
}</p>
<p>static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,<br />
			 int namelen, unsigned long timeout_cs,<br />
			 void (*ast) (void *astparam),<br />
			 void *astparam,<br />
			 void (*bast) (void *astparam, int mode),<br />
			 struct dlm_args *args)<br />
{<br />
	int rv = -EINVAL;</p>
<p>	/* check for invalid arg usage */</p>
<p>	if (mode < 0 || mode > DLM_LOCK_EX)<br />
		goto out;</p>
<p>	if (!(flags &#038; DLM_LKF_CONVERT) &#038;&#038; (namelen > DLM_RESNAME_MAXLEN))<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_CANCEL)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_QUECVT &#038;&#038; !(flags &#038; DLM_LKF_CONVERT))<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_CONVDEADLK &#038;&#038; !(flags &#038; DLM_LKF_CONVERT))<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_CONVDEADLK &#038;&#038; flags &#038; DLM_LKF_NOQUEUE)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_EXPEDITE &#038;&#038; flags &#038; DLM_LKF_CONVERT)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_EXPEDITE &#038;&#038; flags &#038; DLM_LKF_QUECVT)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_EXPEDITE &#038;&#038; flags &#038; DLM_LKF_NOQUEUE)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_EXPEDITE &#038;&#038; mode != DLM_LOCK_NL)<br />
		goto out;</p>
<p>	if (!ast || !lksb)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_VALBLK &#038;&#038; !lksb->sb_lvbptr)<br />
		goto out;</p>
<p>	if (flags &#038; DLM_LKF_CONVERT &#038;&#038; !lksb->sb_lkid)<br />
		goto out;</p>
<p>	/* these args will be copied to the lkb in validate_lock_args,<br />
	   it cannot be done now because when converting locks, fields in<br />
	   an active lkb cannot be modified before locking the rsb */</p>
<p>	args->flags = flags;<br />
	args->astfn = ast;<br />
	args->astparam = astparam;<br />
	args->bastfn = bast;<br />
	args->timeout = timeout_cs;<br />
	args->mode = mode;<br />
	args->lksb = lksb;<br />
	rv = 0;<br />
 out:<br />
	return rv;<br />
}</p>
<p>static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)<br />
{<br />
	if (flags &#038; ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |<br />
 		      DLM_LKF_FORCEUNLOCK))<br />
		return -EINVAL;</p>
<p>	if (flags &#038; DLM_LKF_CANCEL &#038;&#038; flags &#038; DLM_LKF_FORCEUNLOCK)<br />
		return -EINVAL;</p>
<p>	args->flags = flags;<br />
	args->astparam = astarg;<br />
	return 0;<br />
}</p>
<p>static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
			      struct dlm_args *args)<br />
{<br />
	int rv = -EINVAL;</p>
<p>	if (args->flags &#038; DLM_LKF_CONVERT) {<br />
		if (lkb->lkb_flags &#038; DLM_IFL_MSTCPY)<br />
			goto out;</p>
<p>		if (args->flags &#038; DLM_LKF_QUECVT &#038;&#038;<br />
		    !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])<br />
			goto out;</p>
<p>		rv = -EBUSY;<br />
		if (lkb->lkb_status != DLM_LKSTS_GRANTED)<br />
			goto out;</p>
<p>		if (lkb->lkb_wait_type)<br />
			goto out;</p>
<p>		if (is_overlap(lkb))<br />
			goto out;<br />
	}</p>
<p>	lkb->lkb_exflags = args->flags;<br />
	lkb->lkb_sbflags = 0;<br />
	lkb->lkb_astfn = args->astfn;<br />
	lkb->lkb_astparam = args->astparam;<br />
	lkb->lkb_bastfn = args->bastfn;<br />
	lkb->lkb_rqmode = args->mode;<br />
	lkb->lkb_lksb = args->lksb;<br />
	lkb->lkb_lvbptr = args->lksb->sb_lvbptr;<br />
	lkb->lkb_ownpid = (int) current->pid;<br />
	lkb->lkb_timeout_cs = args->timeout;<br />
	rv = 0;<br />
 out:<br />
	if (rv)<br />
		log_debug(ls, &laquo;validate_lock_args %d %x %x %x %d %d %s&raquo;,<br />
			  rv, lkb->lkb_id, lkb->lkb_flags, args->flags,<br />
			  lkb->lkb_status, lkb->lkb_wait_type,<br />
			  lkb->lkb_resource->res_name);<br />
	return rv;<br />
}</p>
<p>/* when dlm_unlock() sees -EBUSY with CANCEL/FORCEUNLOCK it returns 0<br />
   for success */</p>
<p>/* note: it&#8217;s valid for lkb_nodeid/res_nodeid to be -1 when we get here<br />
   because there may be a lookup in progress and it&#8217;s valid to do<br />
   cancel/unlockf on it */</p>
<p>static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)<br />
{<br />
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;<br />
	int rv = -EINVAL;</p>
<p>	if (lkb->lkb_flags &#038; DLM_IFL_MSTCPY) {<br />
		log_error(ls, &laquo;unlock on MSTCPY %x&raquo;, lkb->lkb_id);<br />
		dlm_print_lkb(lkb);<br />
		goto out;<br />
	}</p>
<p>	/* an lkb may still exist even though the lock is EOL&#8217;ed due to a<br />
	   cancel, unlock or failed noqueue request; an app can&#8217;t use these<br />
	   locks; return same error as if the lkid had not been found at all */</p>
<p>	if (lkb->lkb_flags &#038; DLM_IFL_ENDOFLIFE) {<br />
		log_debug(ls, &laquo;unlock on ENDOFLIFE %x&raquo;, lkb->lkb_id);<br />
		rv = -ENOENT;<br />
		goto out;<br />
	}</p>
<p>	/* an lkb may be waiting for an rsb lookup to complete where the<br />
	   lookup was initiated by another lock */</p>
<p>	if (!list_empty(&#038;lkb->lkb_rsb_lookup)) {<br />
		if (args->flags &#038; (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {<br />
			log_debug(ls, &laquo;unlock on rsb_lookup %x&raquo;, lkb->lkb_id);<br />
			list_del_init(&#038;lkb->lkb_rsb_lookup);<br />
			queue_cast(lkb->lkb_resource, lkb,<br />
				   args->flags &#038; DLM_LKF_CANCEL ?<br />
				   -DLM_ECANCEL : -DLM_EUNLOCK);<br />
			unhold_lkb(lkb); /* undoes create_lkb() */<br />
		}<br />
		/* caller changes -EBUSY to 0 for CANCEL and FORCEUNLOCK */<br />
		rv = -EBUSY;<br />
		goto out;<br />
	}</p>
<p>	/* cancel not allowed with another cancel/unlock in progress */</p>
<p>	if (args->flags &#038; DLM_LKF_CANCEL) {<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_CANCEL)<br />
			goto out;</p>
<p>		if (is_overlap(lkb))<br />
			goto out;</p>
<p>		/* don&#8217;t let scand try to do a cancel */<br />
		del_timeout(lkb);</p>
<p>		if (lkb->lkb_flags &#038; DLM_IFL_RESEND) {<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;<br />
			rv = -EBUSY;<br />
			goto out;<br />
		}</p>
<p>		/* there&#8217;s nothing to cancel */<br />
		if (lkb->lkb_status == DLM_LKSTS_GRANTED &#038;&#038;<br />
		    !lkb->lkb_wait_type) {<br />
			rv = -EBUSY;<br />
			goto out;<br />
		}</p>
<p>		switch (lkb->lkb_wait_type) {<br />
		case DLM_MSG_LOOKUP:<br />
		case DLM_MSG_REQUEST:<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;<br />
			rv = -EBUSY;<br />
			goto out;<br />
		case DLM_MSG_UNLOCK:<br />
		case DLM_MSG_CANCEL:<br />
			goto out;<br />
		}<br />
		/* add_to_waiters() will set OVERLAP_CANCEL */<br />
		goto out_ok;<br />
	}</p>
<p>	/* do we need to allow a force-unlock if there&#8217;s a normal unlock<br />
	   already in progress?  in what conditions could the normal unlock<br />
	   fail such that we&#8217;d want to send a force-unlock to be sure? */</p>
<p>	if (args->flags &#038; DLM_LKF_FORCEUNLOCK) {<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_FORCEUNLOCK)<br />
			goto out;</p>
<p>		if (is_overlap_unlock(lkb))<br />
			goto out;</p>
<p>		/* don&#8217;t let scand try to do a cancel */<br />
		del_timeout(lkb);</p>
<p>		if (lkb->lkb_flags &#038; DLM_IFL_RESEND) {<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;<br />
			rv = -EBUSY;<br />
			goto out;<br />
		}</p>
<p>		switch (lkb->lkb_wait_type) {<br />
		case DLM_MSG_LOOKUP:<br />
		case DLM_MSG_REQUEST:<br />
			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;<br />
			rv = -EBUSY;<br />
			goto out;<br />
		case DLM_MSG_UNLOCK:<br />
			goto out;<br />
		}<br />
		/* add_to_waiters() will set OVERLAP_UNLOCK */<br />
		goto out_ok;<br />
	}</p>
<p>	/* normal unlock not allowed if there&#8217;s any op in progress */<br />
	rv = -EBUSY;<br />
	if (lkb->lkb_wait_type || lkb->lkb_wait_count)<br />
		goto out;</p>
<p> out_ok:<br />
	/* an overlapping op shouldn&#8217;t blow away exflags from other op */<br />
	lkb->lkb_exflags |= args->flags;<br />
	lkb->lkb_sbflags = 0;<br />
	lkb->lkb_astparam = args->astparam;<br />
	rv = 0;<br />
 out:<br />
	if (rv)<br />
		log_debug(ls, &laquo;validate_unlock_args %d %x %x %x %x %d %s&raquo;, rv,<br />
			  lkb->lkb_id, lkb->lkb_flags, lkb->lkb_exflags,<br />
			  args->flags, lkb->lkb_wait_type,<br />
			  lkb->lkb_resource->res_name);<br />
	return rv;<br />
}</p>
<p>/*<br />
 * Four stage 4 varieties:<br />
 * do_request(), do_convert(), do_unlock(), do_cancel()<br />
 * These are called on the master node for the given lock and<br />
 * from the central locking logic.<br />
 */</p>
<p>static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error = 0;</p>
<p>	if (can_be_granted(r, lkb, 1, NULL)) {<br />
		grant_lock(r, lkb);<br />
		queue_cast(r, lkb, 0);<br />
		goto out;<br />
	}</p>
<p>	if (can_be_queued(lkb)) {<br />
		error = -EINPROGRESS;<br />
		add_lkb(r, lkb, DLM_LKSTS_WAITING);<br />
		send_blocking_asts(r, lkb);<br />
		add_timeout(lkb);<br />
		goto out;<br />
	}</p>
<p>	error = -EAGAIN;<br />
	if (force_blocking_asts(lkb))<br />
		send_blocking_asts_all(r, lkb);<br />
	queue_cast(r, lkb, -EAGAIN);</p>
<p> out:<br />
	return error;<br />
}</p>
<p>static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error = 0;<br />
	int deadlk = 0;</p>
<p>	/* changing an existing lock may allow others to be granted */</p>
<p>	if (can_be_granted(r, lkb, 1, &#038;deadlk)) {<br />
		grant_lock(r, lkb);<br />
		queue_cast(r, lkb, 0);<br />
		grant_pending_locks(r);<br />
		goto out;<br />
	}</p>
<p>	/* can_be_granted() detected that this lock would block in a conversion<br />
	   deadlock, so we leave it on the granted queue and return EDEADLK in<br />
	   the ast for the convert. */</p>
<p>	if (deadlk) {<br />
		/* it&#8217;s left on the granted queue */<br />
		log_debug(r->res_ls, &laquo;deadlock %x node %d sts%d g%d r%d %s&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_nodeid, lkb->lkb_status,<br />
			  lkb->lkb_grmode, lkb->lkb_rqmode, r->res_name);<br />
		revert_lock(r, lkb);<br />
		queue_cast(r, lkb, -EDEADLK);<br />
		error = -EDEADLK;<br />
		goto out;<br />
	}</p>
<p>	/* is_demoted() means the can_be_granted() above set the grmode<br />
	   to NL, and left us on the granted queue.  This auto-demotion<br />
	   (due to CONVDEADLK) might mean other locks, and/or this lock, are<br />
	   now grantable.  We have to try to grant other converting locks<br />
	   before we try again to grant this one. */</p>
<p>	if (is_demoted(lkb)) {<br />
		grant_pending_convert(r, DLM_LOCK_IV, NULL);<br />
		if (_can_be_granted(r, lkb, 1)) {<br />
			grant_lock(r, lkb);<br />
			queue_cast(r, lkb, 0);<br />
			grant_pending_locks(r);<br />
			goto out;<br />
		}<br />
		/* else fall through and move to convert queue */<br />
	}</p>
<p>	if (can_be_queued(lkb)) {<br />
		error = -EINPROGRESS;<br />
		del_lkb(r, lkb);<br />
		add_lkb(r, lkb, DLM_LKSTS_CONVERT);<br />
		send_blocking_asts(r, lkb);<br />
		add_timeout(lkb);<br />
		goto out;<br />
	}</p>
<p>	error = -EAGAIN;<br />
	if (force_blocking_asts(lkb))<br />
		send_blocking_asts_all(r, lkb);<br />
	queue_cast(r, lkb, -EAGAIN);</p>
<p> out:<br />
	return error;<br />
}</p>
<p>static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	remove_lock(r, lkb);<br />
	queue_cast(r, lkb, -DLM_EUNLOCK);<br />
	grant_pending_locks(r);<br />
	return -DLM_EUNLOCK;<br />
}</p>
<p>/* returns: 0 did nothing, -DLM_ECANCEL canceled lock */</p>
<p>static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	error = revert_lock(r, lkb);<br />
	if (error) {<br />
		queue_cast(r, lkb, -DLM_ECANCEL);<br />
		grant_pending_locks(r);<br />
		return -DLM_ECANCEL;<br />
	}<br />
	return 0;<br />
}</p>
<p>/*<br />
 * Four stage 3 varieties:<br />
 * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()<br />
 */</p>
<p>/* add a new lkb to a possibly new rsb, called by requesting process */</p>
<p>static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	/* set_master: sets lkb nodeid from r */</p>
<p>	error = set_master(r, lkb);<br />
	if (error < 0)<br />
		goto out;<br />
	if (error) {<br />
		error = 0;<br />
		goto out;<br />
	}</p>
<p>	if (is_remote(r))<br />
		/* receive_request() calls do_request() on remote node */<br />
		error = send_request(r, lkb);<br />
	else<br />
		error = do_request(r, lkb);<br />
 out:<br />
	return error;<br />
}</p>
<p>/* change some property of an existing lkb, e.g. mode */</p>
<p>static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	if (is_remote(r))<br />
		/* receive_convert() calls do_convert() on remote node */<br />
		error = send_convert(r, lkb);<br />
	else<br />
		error = do_convert(r, lkb);</p>
<p>	return error;<br />
}</p>
<p>/* remove an existing lkb from the granted queue */</p>
<p>static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	if (is_remote(r))<br />
		/* receive_unlock() calls do_unlock() on remote node */<br />
		error = send_unlock(r, lkb);<br />
	else<br />
		error = do_unlock(r, lkb);</p>
<p>	return error;<br />
}</p>
<p>/* remove an existing lkb from the convert or wait queue */</p>
<p>static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	if (is_remote(r))<br />
		/* receive_cancel() calls do_cancel() on remote node */<br />
		error = send_cancel(r, lkb);<br />
	else<br />
		error = do_cancel(r, lkb);</p>
<p>	return error;<br />
}</p>
<p>/*<br />
 * Four stage 2 varieties:<br />
 * request_lock(), convert_lock(), unlock_lock(), cancel_lock()<br />
 */</p>
<p>static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,<br />
			int len, struct dlm_args *args)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = validate_lock_args(ls, lkb, args);<br />
	if (error)<br />
		goto out;</p>
<p>	error = find_rsb(ls, name, len, R_CREATE, &#038;r);<br />
	if (error)<br />
		goto out;</p>
<p>	lock_rsb(r);</p>
<p>	attach_lkb(r, lkb);<br />
	lkb->lkb_lksb->sb_lkid = lkb->lkb_id;</p>
<p>	error = _request_lock(r, lkb);</p>
<p>	unlock_rsb(r);<br />
	put_rsb(r);</p>
<p> out:<br />
	return error;<br />
}</p>
<p>static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
			struct dlm_args *args)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_lock_args(ls, lkb, args);<br />
	if (error)<br />
		goto out;</p>
<p>	error = _convert_lock(r, lkb);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	return error;<br />
}</p>
<p>static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
		       struct dlm_args *args)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_unlock_args(lkb, args);<br />
	if (error)<br />
		goto out;</p>
<p>	error = _unlock_lock(r, lkb);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	return error;<br />
}</p>
<p>static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
		       struct dlm_args *args)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_unlock_args(lkb, args);<br />
	if (error)<br />
		goto out;</p>
<p>	error = _cancel_lock(r, lkb);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	return error;<br />
}</p>
<p>/*<br />
 * Two stage 1 varieties:  dlm_lock() and dlm_unlock()<br />
 */</p>
<p>int dlm_lock(dlm_lockspace_t *lockspace,<br />
	     int mode,<br />
	     struct dlm_lksb *lksb,<br />
	     uint32_t flags,<br />
	     void *name,<br />
	     unsigned int namelen,<br />
	     uint32_t parent_lkid,<br />
	     void (*ast) (void *astarg),<br />
	     void *astarg,<br />
	     void (*bast) (void *astarg, int mode))<br />
{<br />
	struct dlm_ls *ls;<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	int error, convert = flags &#038; DLM_LKF_CONVERT;</p>
<p>	ls = dlm_find_lockspace_local(lockspace);<br />
	if (!ls)<br />
		return -EINVAL;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	if (convert)<br />
		error = find_lkb(ls, lksb->sb_lkid, &#038;lkb);<br />
	else<br />
		error = create_lkb(ls, &#038;lkb);</p>
<p>	if (error)<br />
		goto out;</p>
<p>	error = set_lock_args(mode, lksb, flags, namelen, 0, ast,<br />
			      astarg, bast, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	if (convert)<br />
		error = convert_lock(ls, lkb, &#038;args);<br />
	else<br />
		error = request_lock(ls, lkb, name, namelen, &#038;args);</p>
<p>	if (error == -EINPROGRESS)<br />
		error = 0;<br />
 out_put:<br />
	if (convert || error)<br />
		__put_lkb(ls, lkb);<br />
	if (error == -EAGAIN || error == -EDEADLK)<br />
		error = 0;<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>int dlm_unlock(dlm_lockspace_t *lockspace,<br />
	       uint32_t lkid,<br />
	       uint32_t flags,<br />
	       struct dlm_lksb *lksb,<br />
	       void *astarg)<br />
{<br />
	struct dlm_ls *ls;<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	int error;</p>
<p>	ls = dlm_find_lockspace_local(lockspace);<br />
	if (!ls)<br />
		return -EINVAL;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = find_lkb(ls, lkid, &#038;lkb);<br />
	if (error)<br />
		goto out;</p>
<p>	error = set_unlock_args(flags, astarg, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	if (flags &#038; DLM_LKF_CANCEL)<br />
		error = cancel_lock(ls, lkb, &#038;args);<br />
	else<br />
		error = unlock_lock(ls, lkb, &#038;args);</p>
<p>	if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)<br />
		error = 0;<br />
	if (error == -EBUSY &#038;&#038; (flags &#038; (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)))<br />
		error = 0;<br />
 out_put:<br />
	dlm_put_lkb(lkb);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>/*<br />
 * send/receive routines for remote operations and replies<br />
 *<br />
 * send_args<br />
 * send_common<br />
 * send_request			receive_request<br />
 * send_convert			receive_convert<br />
 * send_unlock			receive_unlock<br />
 * send_cancel			receive_cancel<br />
 * send_grant			receive_grant<br />
 * send_bast			receive_bast<br />
 * send_lookup			receive_lookup<br />
 * send_remove			receive_remove<br />
 *<br />
 * 				send_common_reply<br />
 * receive_request_reply	send_request_reply<br />
 * receive_convert_reply	send_convert_reply<br />
 * receive_unlock_reply		send_unlock_reply<br />
 * receive_cancel_reply		send_cancel_reply<br />
 * receive_lookup_reply		send_lookup_reply<br />
 */</p>
<p>static int _create_message(struct dlm_ls *ls, int mb_len,<br />
			   int to_nodeid, int mstype,<br />
			   struct dlm_message **ms_ret,<br />
			   struct dlm_mhandle **mh_ret)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	char *mb;</p>
<p>	/* get_buffer gives us a message handle (mh) that we need to<br />
	   pass into lowcomms_commit and a message buffer (mb) that we<br />
	   write our data into */</p>
<p>	mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, ls->ls_allocation, &#038;mb);<br />
	if (!mh)<br />
		return -ENOBUFS;</p>
<p>	memset(mb, 0, mb_len);</p>
<p>	ms = (struct dlm_message *) mb;</p>
<p>	ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);<br />
	ms->m_header.h_lockspace = ls->ls_global_id;<br />
	ms->m_header.h_nodeid = dlm_our_nodeid();<br />
	ms->m_header.h_length = mb_len;<br />
	ms->m_header.h_cmd = DLM_MSG;</p>
<p>	ms->m_type = mstype;</p>
<p>	*mh_ret = mh;<br />
	*ms_ret = ms;<br />
	return 0;<br />
}</p>
<p>static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
			  int to_nodeid, int mstype,<br />
			  struct dlm_message **ms_ret,<br />
			  struct dlm_mhandle **mh_ret)<br />
{<br />
	int mb_len = sizeof(struct dlm_message);</p>
<p>	switch (mstype) {<br />
	case DLM_MSG_REQUEST:<br />
	case DLM_MSG_LOOKUP:<br />
	case DLM_MSG_REMOVE:<br />
		mb_len += r->res_length;<br />
		break;<br />
	case DLM_MSG_CONVERT:<br />
	case DLM_MSG_UNLOCK:<br />
	case DLM_MSG_REQUEST_REPLY:<br />
	case DLM_MSG_CONVERT_REPLY:<br />
	case DLM_MSG_GRANT:<br />
		if (lkb &#038;&#038; lkb->lkb_lvbptr)<br />
			mb_len += r->res_ls->ls_lvblen;<br />
		break;<br />
	}</p>
<p>	return _create_message(r->res_ls, mb_len, to_nodeid, mstype,<br />
			       ms_ret, mh_ret);<br />
}</p>
<p>/* further lowcomms enhancements or alternate implementations may make<br />
   the return value from this function useful at some point */</p>
<p>static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)<br />
{<br />
	dlm_message_out(ms);<br />
	dlm_lowcomms_commit_buffer(mh);<br />
	return 0;<br />
}</p>
<p>static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
		      struct dlm_message *ms)<br />
{<br />
	ms->m_nodeid   = lkb->lkb_nodeid;<br />
	ms->m_pid      = lkb->lkb_ownpid;<br />
	ms->m_lkid     = lkb->lkb_id;<br />
	ms->m_remid    = lkb->lkb_remid;<br />
	ms->m_exflags  = lkb->lkb_exflags;<br />
	ms->m_sbflags  = lkb->lkb_sbflags;<br />
	ms->m_flags    = lkb->lkb_flags;<br />
	ms->m_lvbseq   = lkb->lkb_lvbseq;<br />
	ms->m_status   = lkb->lkb_status;<br />
	ms->m_grmode   = lkb->lkb_grmode;<br />
	ms->m_rqmode   = lkb->lkb_rqmode;<br />
	ms->m_hash     = r->res_hash;</p>
<p>	/* m_result and m_bastmode are set from function args,<br />
	   not from lkb fields */</p>
<p>	if (lkb->lkb_bastfn)<br />
		ms->m_asts |= AST_BAST;<br />
	if (lkb->lkb_astfn)<br />
		ms->m_asts |= AST_COMP;</p>
<p>	/* compare with switch in create_message; send_remove() doesn&#8217;t<br />
	   use send_args() */</p>
<p>	switch (ms->m_type) {<br />
	case DLM_MSG_REQUEST:<br />
	case DLM_MSG_LOOKUP:<br />
		memcpy(ms->m_extra, r->res_name, r->res_length);<br />
		break;<br />
	case DLM_MSG_CONVERT:<br />
	case DLM_MSG_UNLOCK:<br />
	case DLM_MSG_REQUEST_REPLY:<br />
	case DLM_MSG_CONVERT_REPLY:<br />
	case DLM_MSG_GRANT:<br />
		if (!lkb->lkb_lvbptr)<br />
			break;<br />
		memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);<br />
		break;<br />
	}<br />
}</p>
<p>static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	error = add_to_waiters(lkb, mstype);<br />
	if (error)<br />
		return error;</p>
<p>	to_nodeid = r->res_nodeid;</p>
<p>	error = create_message(r, lkb, to_nodeid, mstype, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto fail;</p>
<p>	send_args(r, lkb, ms);</p>
<p>	error = send_message(mh, ms);<br />
	if (error)<br />
		goto fail;<br />
	return 0;</p>
<p> fail:<br />
	remove_from_waiters(lkb, msg_reply_type(mstype));<br />
	return error;<br />
}</p>
<p>static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	return send_common(r, lkb, DLM_MSG_REQUEST);<br />
}</p>
<p>static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	int error;</p>
<p>	error = send_common(r, lkb, DLM_MSG_CONVERT);</p>
<p>	/* down conversions go without a reply from the master */<br />
	if (!error &#038;&#038; down_conversion(lkb)) {<br />
		remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);<br />
		r->res_ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;<br />
		r->res_ls->ls_stub_ms.m_result = 0;<br />
		r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;<br />
		__receive_convert_reply(r, lkb, &#038;r->res_ls->ls_stub_ms);<br />
	}</p>
<p>	return error;<br />
}</p>
<p>/* FIXME: if this lkb is the only lock we hold on the rsb, then set<br />
   MASTER_UNCERTAIN to force the next request on the rsb to confirm<br />
   that the master is still correct. */</p>
<p>static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	return send_common(r, lkb, DLM_MSG_UNLOCK);<br />
}</p>
<p>static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	return send_common(r, lkb, DLM_MSG_CANCEL);<br />
}</p>
<p>static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	to_nodeid = lkb->lkb_nodeid;</p>
<p>	error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto out;</p>
<p>	send_args(r, lkb, ms);</p>
<p>	ms->m_result = 0;</p>
<p>	error = send_message(mh, ms);<br />
 out:<br />
	return error;<br />
}</p>
<p>static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	to_nodeid = lkb->lkb_nodeid;</p>
<p>	error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto out;</p>
<p>	send_args(r, lkb, ms);</p>
<p>	ms->m_bastmode = mode;</p>
<p>	error = send_message(mh, ms);<br />
 out:<br />
	return error;<br />
}</p>
<p>static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	error = add_to_waiters(lkb, DLM_MSG_LOOKUP);<br />
	if (error)<br />
		return error;</p>
<p>	to_nodeid = dlm_dir_nodeid(r);</p>
<p>	error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto fail;</p>
<p>	send_args(r, lkb, ms);</p>
<p>	error = send_message(mh, ms);<br />
	if (error)<br />
		goto fail;<br />
	return 0;</p>
<p> fail:<br />
	remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);<br />
	return error;<br />
}</p>
<p>static int send_remove(struct dlm_rsb *r)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	to_nodeid = dlm_dir_nodeid(r);</p>
<p>	error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto out;</p>
<p>	memcpy(ms->m_extra, r->res_name, r->res_length);<br />
	ms->m_hash = r->res_hash;</p>
<p>	error = send_message(mh, ms);<br />
 out:<br />
	return error;<br />
}</p>
<p>static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
			     int mstype, int rv)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int to_nodeid, error;</p>
<p>	to_nodeid = lkb->lkb_nodeid;</p>
<p>	error = create_message(r, lkb, to_nodeid, mstype, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto out;</p>
<p>	send_args(r, lkb, ms);</p>
<p>	ms->m_result = rv;</p>
<p>	error = send_message(mh, ms);<br />
 out:<br />
	return error;<br />
}</p>
<p>static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)<br />
{<br />
	return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);<br />
}</p>
<p>static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)<br />
{<br />
	return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);<br />
}</p>
<p>static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)<br />
{<br />
	return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);<br />
}</p>
<p>static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)<br />
{<br />
	return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);<br />
}</p>
<p>static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,<br />
			     int ret_nodeid, int rv)<br />
{<br />
	struct dlm_rsb *r = &#038;ls->ls_stub_rsb;<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int error, nodeid = ms_in->m_header.h_nodeid;</p>
<p>	error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &#038;ms, &#038;mh);<br />
	if (error)<br />
		goto out;</p>
<p>	ms->m_lkid = ms_in->m_lkid;<br />
	ms->m_result = rv;<br />
	ms->m_nodeid = ret_nodeid;</p>
<p>	error = send_message(mh, ms);<br />
 out:<br />
	return error;<br />
}</p>
<p>/* which args we save from a received message depends heavily on the type<br />
   of message, unlike the send side where we can safely send everything about<br />
   the lkb for any type of message */</p>
<p>static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	lkb->lkb_exflags = ms->m_exflags;<br />
	lkb->lkb_sbflags = ms->m_sbflags;<br />
	lkb->lkb_flags = (lkb->lkb_flags &#038; 0xFFFF0000) |<br />
		         (ms->m_flags &#038; 0&#215;0000FFFF);<br />
}</p>
<p>static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	lkb->lkb_sbflags = ms->m_sbflags;<br />
	lkb->lkb_flags = (lkb->lkb_flags &#038; 0xFFFF0000) |<br />
		         (ms->m_flags &#038; 0&#215;0000FFFF);<br />
}</p>
<p>static int receive_extralen(struct dlm_message *ms)<br />
{<br />
	return (ms->m_header.h_length &#8211; sizeof(struct dlm_message));<br />
}</p>
<p>static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
		       struct dlm_message *ms)<br />
{<br />
	int len;</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_VALBLK) {<br />
		if (!lkb->lkb_lvbptr)<br />
			lkb->lkb_lvbptr = dlm_allocate_lvb(ls);<br />
		if (!lkb->lkb_lvbptr)<br />
			return -ENOMEM;<br />
		len = receive_extralen(ms);<br />
		if (len > DLM_RESNAME_MAXLEN)<br />
			len = DLM_RESNAME_MAXLEN;<br />
		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);<br />
	}<br />
	return 0;<br />
}</p>
<p>static void fake_bastfn(void *astparam, int mode)<br />
{<br />
	log_print(&raquo;fake_bastfn should not be called&raquo;);<br />
}</p>
<p>static void fake_astfn(void *astparam)<br />
{<br />
	log_print(&raquo;fake_astfn should not be called&raquo;);<br />
}</p>
<p>static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
				struct dlm_message *ms)<br />
{<br />
	lkb->lkb_nodeid = ms->m_header.h_nodeid;<br />
	lkb->lkb_ownpid = ms->m_pid;<br />
	lkb->lkb_remid = ms->m_lkid;<br />
	lkb->lkb_grmode = DLM_LOCK_IV;<br />
	lkb->lkb_rqmode = ms->m_rqmode;</p>
<p>	lkb->lkb_bastfn = (ms->m_asts &#038; AST_BAST) ? &#038;fake_bastfn : NULL;<br />
	lkb->lkb_astfn = (ms->m_asts &#038; AST_COMP) ? &#038;fake_astfn : NULL;</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_VALBLK) {<br />
		/* lkb was just created so there won&#8217;t be an lvb yet */<br />
		lkb->lkb_lvbptr = dlm_allocate_lvb(ls);<br />
		if (!lkb->lkb_lvbptr)<br />
			return -ENOMEM;<br />
	}</p>
<p>	return 0;<br />
}</p>
<p>static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
				struct dlm_message *ms)<br />
{<br />
	if (lkb->lkb_status != DLM_LKSTS_GRANTED)<br />
		return -EBUSY;</p>
<p>	if (receive_lvb(ls, lkb, ms))<br />
		return -ENOMEM;</p>
<p>	lkb->lkb_rqmode = ms->m_rqmode;<br />
	lkb->lkb_lvbseq = ms->m_lvbseq;</p>
<p>	return 0;<br />
}</p>
<p>static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
			       struct dlm_message *ms)<br />
{<br />
	if (receive_lvb(ls, lkb, ms))<br />
		return -ENOMEM;<br />
	return 0;<br />
}</p>
<p>/* We fill in the stub-lkb fields with the info that send_xxxx_reply()<br />
   uses to send a reply and that the remote end uses to process the reply. */</p>
<p>static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb = &#038;ls->ls_stub_lkb;<br />
	lkb->lkb_nodeid = ms->m_header.h_nodeid;<br />
	lkb->lkb_remid = ms->m_lkid;<br />
}</p>
<p>/* This is called after the rsb is locked so that we can safely inspect<br />
   fields in the lkb. */</p>
<p>static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	int from = ms->m_header.h_nodeid;<br />
	int error = 0;</p>
<p>	switch (ms->m_type) {<br />
	case DLM_MSG_CONVERT:<br />
	case DLM_MSG_UNLOCK:<br />
	case DLM_MSG_CANCEL:<br />
		if (!is_master_copy(lkb) || lkb->lkb_nodeid != from)<br />
			error = -EINVAL;<br />
		break;</p>
<p>	case DLM_MSG_CONVERT_REPLY:<br />
	case DLM_MSG_UNLOCK_REPLY:<br />
	case DLM_MSG_CANCEL_REPLY:<br />
	case DLM_MSG_GRANT:<br />
	case DLM_MSG_BAST:<br />
		if (!is_process_copy(lkb) || lkb->lkb_nodeid != from)<br />
			error = -EINVAL;<br />
		break;</p>
<p>	case DLM_MSG_REQUEST_REPLY:<br />
		if (!is_process_copy(lkb))<br />
			error = -EINVAL;<br />
		else if (lkb->lkb_nodeid != -1 &#038;&#038; lkb->lkb_nodeid != from)<br />
			error = -EINVAL;<br />
		break;</p>
<p>	default:<br />
		error = -EINVAL;<br />
	}</p>
<p>	if (error)<br />
		log_error(lkb->lkb_resource->res_ls,<br />
			  &laquo;ignore invalid message %d from %d %x %x %x %d&raquo;,<br />
			  ms->m_type, from, lkb->lkb_id, lkb->lkb_remid,<br />
			  lkb->lkb_flags, lkb->lkb_nodeid);<br />
	return error;<br />
}</p>
<p>static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error, namelen;</p>
<p>	error = create_lkb(ls, &#038;lkb);<br />
	if (error)<br />
		goto fail;</p>
<p>	receive_flags(lkb, ms);<br />
	lkb->lkb_flags |= DLM_IFL_MSTCPY;<br />
	error = receive_request_args(ls, lkb, ms);<br />
	if (error) {<br />
		__put_lkb(ls, lkb);<br />
		goto fail;<br />
	}</p>
<p>	namelen = receive_extralen(ms);</p>
<p>	error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &#038;r);<br />
	if (error) {<br />
		__put_lkb(ls, lkb);<br />
		goto fail;<br />
	}</p>
<p>	lock_rsb(r);</p>
<p>	attach_lkb(r, lkb);<br />
	error = do_request(r, lkb);<br />
	send_request_reply(r, lkb, error);</p>
<p>	unlock_rsb(r);<br />
	put_rsb(r);</p>
<p>	if (error == -EINPROGRESS)<br />
		error = 0;<br />
	if (error)<br />
		dlm_put_lkb(lkb);<br />
	return;</p>
<p> fail:<br />
	setup_stub_lkb(ls, ms);<br />
	send_request_reply(&#038;ls->ls_stub_rsb, &#038;ls->ls_stub_lkb, error);<br />
}</p>
<p>static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error, reply = 1;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error)<br />
		goto fail;</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	receive_flags(lkb, ms);<br />
	error = receive_convert_args(ls, lkb, ms);<br />
	if (error)<br />
		goto out_reply;<br />
	reply = !down_conversion(lkb);</p>
<p>	error = do_convert(r, lkb);<br />
 out_reply:<br />
	if (reply)<br />
		send_convert_reply(r, lkb, error);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
	return;</p>
<p> fail:<br />
	setup_stub_lkb(ls, ms);<br />
	send_convert_reply(&#038;ls->ls_stub_rsb, &#038;ls->ls_stub_lkb, error);<br />
}</p>
<p>static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error)<br />
		goto fail;</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	receive_flags(lkb, ms);<br />
	error = receive_unlock_args(ls, lkb, ms);<br />
	if (error)<br />
		goto out_reply;</p>
<p>	error = do_unlock(r, lkb);<br />
 out_reply:<br />
	send_unlock_reply(r, lkb, error);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
	return;</p>
<p> fail:<br />
	setup_stub_lkb(ls, ms);<br />
	send_unlock_reply(&#038;ls->ls_stub_rsb, &#038;ls->ls_stub_lkb, error);<br />
}</p>
<p>static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error)<br />
		goto fail;</p>
<p>	receive_flags(lkb, ms);</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	error = do_cancel(r, lkb);<br />
	send_cancel_reply(r, lkb, error);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
	return;</p>
<p> fail:<br />
	setup_stub_lkb(ls, ms);<br />
	send_cancel_reply(&#038;ls->ls_stub_rsb, &#038;ls->ls_stub_lkb, error);<br />
}</p>
<p>static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_grant from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	receive_flags_reply(lkb, ms);<br />
	if (is_altmode(lkb))<br />
		munge_altmode(lkb, ms);<br />
	grant_lock_pc(r, lkb, ms);<br />
	queue_cast(r, lkb, 0);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_bast from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	r = lkb->lkb_resource;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	queue_bast(r, lkb, ms->m_bastmode);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;</p>
<p>	from_nodeid = ms->m_header.h_nodeid;<br />
	our_nodeid = dlm_our_nodeid();</p>
<p>	len = receive_extralen(ms);</p>
<p>	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);<br />
	if (dir_nodeid != our_nodeid) {<br />
		log_error(ls, &laquo;lookup dir_nodeid %d from %d&raquo;,<br />
			  dir_nodeid, from_nodeid);<br />
		error = -EINVAL;<br />
		ret_nodeid = -1;<br />
		goto out;<br />
	}</p>
<p>	error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &#038;ret_nodeid);</p>
<p>	/* Optimization: we&#8217;re master so treat lookup as a request */<br />
	if (!error &#038;&#038; ret_nodeid == our_nodeid) {<br />
		receive_request(ls, ms);<br />
		return;<br />
	}<br />
 out:<br />
	send_lookup_reply(ls, ms, ret_nodeid, error);<br />
}</p>
<p>static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	int len, dir_nodeid, from_nodeid;</p>
<p>	from_nodeid = ms->m_header.h_nodeid;</p>
<p>	len = receive_extralen(ms);</p>
<p>	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);<br />
	if (dir_nodeid != dlm_our_nodeid()) {<br />
		log_error(ls, &laquo;remove dir entry dir_nodeid %d from %d&raquo;,<br />
			  dir_nodeid, from_nodeid);<br />
		return;<br />
	}</p>
<p>	dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);<br />
}</p>
<p>static void receive_purge(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	do_purge(ls, ms->m_nodeid, ms->m_pid);<br />
}</p>
<p>static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error, mstype, result;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_request_reply from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	r = lkb->lkb_resource;<br />
	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	mstype = lkb->lkb_wait_type;<br />
	error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);<br />
	if (error)<br />
		goto out;</p>
<p>	/* Optimization: the dir node was also the master, so it took our<br />
	   lookup as a request and sent request reply instead of lookup reply */<br />
	if (mstype == DLM_MSG_LOOKUP) {<br />
		r->res_nodeid = ms->m_header.h_nodeid;<br />
		lkb->lkb_nodeid = r->res_nodeid;<br />
	}</p>
<p>	/* this is the value returned from do_request() on the master */<br />
	result = ms->m_result;</p>
<p>	switch (result) {<br />
	case -EAGAIN:<br />
		/* request would block (be queued) on remote master */<br />
		queue_cast(r, lkb, -EAGAIN);<br />
		confirm_master(r, -EAGAIN);<br />
		unhold_lkb(lkb); /* undoes create_lkb() */<br />
		break;</p>
<p>	case -EINPROGRESS:<br />
	case 0:<br />
		/* request was queued or granted on remote master */<br />
		receive_flags_reply(lkb, ms);<br />
		lkb->lkb_remid = ms->m_lkid;<br />
		if (is_altmode(lkb))<br />
			munge_altmode(lkb, ms);<br />
		if (result) {<br />
			add_lkb(r, lkb, DLM_LKSTS_WAITING);<br />
			add_timeout(lkb);<br />
		} else {<br />
			grant_lock_pc(r, lkb, ms);<br />
			queue_cast(r, lkb, 0);<br />
		}<br />
		confirm_master(r, result);<br />
		break;</p>
<p>	case -EBADR:<br />
	case -ENOTBLK:<br />
		/* find_rsb failed to find rsb or rsb wasn&#8217;t master */<br />
		log_debug(ls, &laquo;receive_request_reply %x %x master diff %d %d&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_flags, r->res_nodeid, result);<br />
		r->res_nodeid = -1;<br />
		lkb->lkb_nodeid = -1;</p>
<p>		if (is_overlap(lkb)) {<br />
			/* we&#8217;ll ignore error in cancel/unlock reply */<br />
			queue_cast_overlap(r, lkb);<br />
			confirm_master(r, result);<br />
			unhold_lkb(lkb); /* undoes create_lkb() */<br />
		} else<br />
			_request_lock(r, lkb);<br />
		break;</p>
<p>	default:<br />
		log_error(ls, &laquo;receive_request_reply %x error %d&raquo;,<br />
			  lkb->lkb_id, result);<br />
	}</p>
<p>	if (is_overlap_unlock(lkb) &#038;&#038; (result == 0 || result == -EINPROGRESS)) {<br />
		log_debug(ls, &laquo;receive_request_reply %x result %d unlock&raquo;,<br />
			  lkb->lkb_id, result);<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_UNLOCK;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		send_unlock(r, lkb);<br />
	} else if (is_overlap_cancel(lkb) &#038;&#038; (result == -EINPROGRESS)) {<br />
		log_debug(ls, &laquo;receive_request_reply %x cancel&raquo;, lkb->lkb_id);<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_UNLOCK;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		send_cancel(r, lkb);<br />
	} else {<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_UNLOCK;<br />
	}<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,<br />
				    struct dlm_message *ms)<br />
{<br />
	/* this is the value returned from do_convert() on the master */<br />
	switch (ms->m_result) {<br />
	case -EAGAIN:<br />
		/* convert would block (be queued) on remote master */<br />
		queue_cast(r, lkb, -EAGAIN);<br />
		break;</p>
<p>	case -EDEADLK:<br />
		receive_flags_reply(lkb, ms);<br />
		revert_lock_pc(r, lkb);<br />
		queue_cast(r, lkb, -EDEADLK);<br />
		break;</p>
<p>	case -EINPROGRESS:<br />
		/* convert was queued on remote master */<br />
		receive_flags_reply(lkb, ms);<br />
		if (is_demoted(lkb))<br />
			munge_demoted(lkb, ms);<br />
		del_lkb(r, lkb);<br />
		add_lkb(r, lkb, DLM_LKSTS_CONVERT);<br />
		add_timeout(lkb);<br />
		break;</p>
<p>	case 0:<br />
		/* convert was granted on remote master */<br />
		receive_flags_reply(lkb, ms);<br />
		if (is_demoted(lkb))<br />
			munge_demoted(lkb, ms);<br />
		grant_lock_pc(r, lkb, ms);<br />
		queue_cast(r, lkb, 0);<br />
		break;</p>
<p>	default:<br />
		log_error(r->res_ls, &laquo;receive_convert_reply %x error %d&raquo;,<br />
			  lkb->lkb_id, ms->m_result);<br />
	}<br />
}</p>
<p>static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	struct dlm_rsb *r = lkb->lkb_resource;<br />
	int error;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	/* stub reply can happen with waiters_mutex held */<br />
	error = remove_from_waiters_ms(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	__receive_convert_reply(r, lkb, ms);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
}</p>
<p>static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_convert_reply from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	_receive_convert_reply(lkb, ms);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	struct dlm_rsb *r = lkb->lkb_resource;<br />
	int error;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	/* stub reply can happen with waiters_mutex held */<br />
	error = remove_from_waiters_ms(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	/* this is the value returned from do_unlock() on the master */</p>
<p>	switch (ms->m_result) {<br />
	case -DLM_EUNLOCK:<br />
		receive_flags_reply(lkb, ms);<br />
		remove_lock_pc(r, lkb);<br />
		queue_cast(r, lkb, -DLM_EUNLOCK);<br />
		break;<br />
	case -ENOENT:<br />
		break;<br />
	default:<br />
		log_error(r->res_ls, &laquo;receive_unlock_reply %x error %d&raquo;,<br />
			  lkb->lkb_id, ms->m_result);<br />
	}<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
}</p>
<p>static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_unlock_reply from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	_receive_unlock_reply(lkb, ms);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)<br />
{<br />
	struct dlm_rsb *r = lkb->lkb_resource;<br />
	int error;</p>
<p>	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_message(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	/* stub reply can happen with waiters_mutex held */<br />
	error = remove_from_waiters_ms(lkb, ms);<br />
	if (error)<br />
		goto out;</p>
<p>	/* this is the value returned from do_cancel() on the master */</p>
<p>	switch (ms->m_result) {<br />
	case -DLM_ECANCEL:<br />
		receive_flags_reply(lkb, ms);<br />
		revert_lock_pc(r, lkb);<br />
		queue_cast(r, lkb, -DLM_ECANCEL);<br />
		break;<br />
	case 0:<br />
		break;<br />
	default:<br />
		log_error(r->res_ls, &laquo;receive_cancel_reply %x error %d&raquo;,<br />
			  lkb->lkb_id, ms->m_result);<br />
	}<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
}</p>
<p>static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int error;</p>
<p>	error = find_lkb(ls, ms->m_remid, &#038;lkb);<br />
	if (error) {<br />
		log_debug(ls, &laquo;receive_cancel_reply from %d no lkb %x&raquo;,<br />
			  ms->m_header.h_nodeid, ms->m_remid);<br />
		return;<br />
	}</p>
<p>	_receive_cancel_reply(lkb, ms);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error, ret_nodeid;</p>
<p>	error = find_lkb(ls, ms->m_lkid, &#038;lkb);<br />
	if (error) {<br />
		log_error(ls, &laquo;receive_lookup_reply no lkb&raquo;);<br />
		return;<br />
	}</p>
<p>	/* ms->m_result is the value returned by dlm_dir_lookup on dir node<br />
	   FIXME: will a non-zero error ever be returned? */</p>
<p>	r = lkb->lkb_resource;<br />
	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);<br />
	if (error)<br />
		goto out;</p>
<p>	ret_nodeid = ms->m_nodeid;<br />
	if (ret_nodeid == dlm_our_nodeid()) {<br />
		r->res_nodeid = 0;<br />
		ret_nodeid = 0;<br />
		r->res_first_lkid = 0;<br />
	} else {<br />
		/* set_master() will copy res_nodeid to lkb_nodeid */<br />
		r->res_nodeid = ret_nodeid;<br />
	}</p>
<p>	if (is_overlap(lkb)) {<br />
		log_debug(ls, &laquo;receive_lookup_reply %x unlock %x&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_flags);<br />
		queue_cast_overlap(r, lkb);<br />
		unhold_lkb(lkb); /* undoes create_lkb() */<br />
		goto out_list;<br />
	}</p>
<p>	_request_lock(r, lkb);</p>
<p> out_list:<br />
	if (!ret_nodeid)<br />
		process_lookup_list(r);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);<br />
}</p>
<p>static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	if (!dlm_is_member(ls, ms->m_header.h_nodeid)) {<br />
		log_debug(ls, &laquo;ignore non-member message %d from %d %x %x %d&raquo;,<br />
			  ms->m_type, ms->m_header.h_nodeid, ms->m_lkid,<br />
			  ms->m_remid, ms->m_result);<br />
		return;<br />
	}</p>
<p>	switch (ms->m_type) {</p>
<p>	/* messages sent to a master node */</p>
<p>	case DLM_MSG_REQUEST:<br />
		receive_request(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_CONVERT:<br />
		receive_convert(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_UNLOCK:<br />
		receive_unlock(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_CANCEL:<br />
		receive_cancel(ls, ms);<br />
		break;</p>
<p>	/* messages sent from a master node (replies to above) */</p>
<p>	case DLM_MSG_REQUEST_REPLY:<br />
		receive_request_reply(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_CONVERT_REPLY:<br />
		receive_convert_reply(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_UNLOCK_REPLY:<br />
		receive_unlock_reply(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_CANCEL_REPLY:<br />
		receive_cancel_reply(ls, ms);<br />
		break;</p>
<p>	/* messages sent from a master node (only two types of async msg) */</p>
<p>	case DLM_MSG_GRANT:<br />
		receive_grant(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_BAST:<br />
		receive_bast(ls, ms);<br />
		break;</p>
<p>	/* messages sent to a dir node */</p>
<p>	case DLM_MSG_LOOKUP:<br />
		receive_lookup(ls, ms);<br />
		break;</p>
<p>	case DLM_MSG_REMOVE:<br />
		receive_remove(ls, ms);<br />
		break;</p>
<p>	/* messages sent from a dir node (remove has no reply) */</p>
<p>	case DLM_MSG_LOOKUP_REPLY:<br />
		receive_lookup_reply(ls, ms);<br />
		break;</p>
<p>	/* other messages */</p>
<p>	case DLM_MSG_PURGE:<br />
		receive_purge(ls, ms);<br />
		break;</p>
<p>	default:<br />
		log_error(ls, &laquo;unknown message type %d&raquo;, ms->m_type);<br />
	}</p>
<p>	dlm_astd_wake();<br />
}</p>
<p>/* If the lockspace is in recovery mode (locking stopped), then normal<br />
   messages are saved on the requestqueue for processing after recovery is<br />
   done.  When not in recovery mode, we wait for dlm_recoverd to drain saved<br />
   messages off the requestqueue before we process new ones. This occurs right<br />
   after recovery completes when we transition from saving all messages on<br />
   requestqueue, to processing all the saved messages, to processing new<br />
   messages as they arrive. */</p>
<p>static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,<br />
				int nodeid)<br />
{<br />
	if (dlm_locking_stopped(ls)) {<br />
		dlm_add_requestqueue(ls, nodeid, ms);<br />
	} else {<br />
		dlm_wait_requestqueue(ls);<br />
		_receive_message(ls, ms);<br />
	}<br />
}</p>
<p>/* This is called by dlm_recoverd to process messages that were saved on<br />
   the requestqueue. */</p>
<p>void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)<br />
{<br />
	_receive_message(ls, ms);<br />
}</p>
<p>/* This is called by the midcomms layer when something is received for<br />
   the lockspace.  It could be either a MSG (normal message sent as part of<br />
   standard locking activity) or an RCOM (recovery message sent as part of<br />
   lockspace recovery). */</p>
<p>void dlm_receive_buffer(union dlm_packet *p, int nodeid)<br />
{<br />
	struct dlm_header *hd = &#038;p->header;<br />
	struct dlm_ls *ls;<br />
	int type = 0;</p>
<p>	switch (hd->h_cmd) {<br />
	case DLM_MSG:<br />
		dlm_message_in(&#038;p->message);<br />
		type = p->message.m_type;<br />
		break;<br />
	case DLM_RCOM:<br />
		dlm_rcom_in(&#038;p->rcom);<br />
		type = p->rcom.rc_type;<br />
		break;<br />
	default:<br />
		log_print(&raquo;invalid h_cmd %d from %u&raquo;, hd->h_cmd, nodeid);<br />
		return;<br />
	}</p>
<p>	if (hd->h_nodeid != nodeid) {<br />
		log_print(&raquo;invalid h_nodeid %d from %d lockspace %x&raquo;,<br />
			  hd->h_nodeid, nodeid, hd->h_lockspace);<br />
		return;<br />
	}</p>
<p>	ls = dlm_find_lockspace_global(hd->h_lockspace);<br />
	if (!ls) {<br />
		if (dlm_config.ci_log_debug)<br />
			log_print(&raquo;invalid lockspace %x from %d cmd %d type %d&raquo;,<br />
				  hd->h_lockspace, nodeid, hd->h_cmd, type);</p>
<p>		if (hd->h_cmd == DLM_RCOM &#038;&#038; type == DLM_RCOM_STATUS)<br />
			dlm_send_ls_not_ready(nodeid, &#038;p->rcom);<br />
		return;<br />
	}</p>
<p>	/* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to<br />
	   be inactive (in this ls) before transitioning to recovery mode */</p>
<p>	down_read(&#038;ls->ls_recv_active);<br />
	if (hd->h_cmd == DLM_MSG)<br />
		dlm_receive_message(ls, &#038;p->message, nodeid);<br />
	else<br />
		dlm_receive_rcom(ls, &#038;p->rcom, nodeid);<br />
	up_read(&#038;ls->ls_recv_active);</p>
<p>	dlm_put_lockspace(ls);<br />
}</p>
<p>static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	if (middle_conversion(lkb)) {<br />
		hold_lkb(lkb);<br />
		ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;<br />
		ls->ls_stub_ms.m_result = -EINPROGRESS;<br />
		ls->ls_stub_ms.m_flags = lkb->lkb_flags;<br />
		ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;<br />
		_receive_convert_reply(lkb, &#038;ls->ls_stub_ms);</p>
<p>		/* Same special case as in receive_rcom_lock_args() */<br />
		lkb->lkb_grmode = DLM_LOCK_IV;<br />
		rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);<br />
		unhold_lkb(lkb);</p>
<p>	} else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {<br />
		lkb->lkb_flags |= DLM_IFL_RESEND;<br />
	}</p>
<p>	/* lkb->lkb_rqmode < lkb->lkb_grmode shouldn&#8217;t happen since down<br />
	   conversions are async; there&#8217;s no reply from the remote master */<br />
}</p>
<p>/* A waiting lkb needs recovery if the master node has failed, or<br />
   the master node is changing (only when no directory is used) */</p>
<p>static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	if (dlm_is_removed(ls, lkb->lkb_nodeid))<br />
		return 1;</p>
<p>	if (!dlm_no_directory(ls))<br />
		return 0;</p>
<p>	if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)<br />
		return 1;</p>
<p>	return 0;<br />
}</p>
<p>/* Recovery for locks that are waiting for replies from nodes that are now<br />
   gone.  We can just complete unlocks and cancels by faking a reply from the<br />
   dead node.  Requests and up-conversions we flag to be resent after<br />
   recovery.  Down-conversions can just be completed with a fake reply like<br />
   unlocks.  Conversions between PR and CW need special attention. */</p>
<p>void dlm_recover_waiters_pre(struct dlm_ls *ls)<br />
{<br />
	struct dlm_lkb *lkb, *safe;<br />
	int wait_type, stub_unlock_result, stub_cancel_result;</p>
<p>	mutex_lock(&#038;ls->ls_waiters_mutex);</p>
<p>	list_for_each_entry_safe(lkb, safe, &#038;ls->ls_waiters, lkb_wait_reply) {<br />
		log_debug(ls, &laquo;pre recover waiter lkid %x type %d flags %x&raquo;,<br />
			  lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);</p>
<p>		/* all outstanding lookups, regardless of destination  will be<br />
		   resent after recovery is done */</p>
<p>		if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {<br />
			lkb->lkb_flags |= DLM_IFL_RESEND;<br />
			continue;<br />
		}</p>
<p>		if (!waiter_needs_recovery(ls, lkb))<br />
			continue;</p>
<p>		wait_type = lkb->lkb_wait_type;<br />
		stub_unlock_result = -DLM_EUNLOCK;<br />
		stub_cancel_result = -DLM_ECANCEL;</p>
<p>		/* Main reply may have been received leaving a zero wait_type,<br />
		   but a reply for the overlapping op may not have been<br />
		   received.  In that case we need to fake the appropriate<br />
		   reply for the overlap op. */</p>
<p>		if (!wait_type) {<br />
			if (is_overlap_cancel(lkb)) {<br />
				wait_type = DLM_MSG_CANCEL;<br />
				if (lkb->lkb_grmode == DLM_LOCK_IV)<br />
					stub_cancel_result = 0;<br />
			}<br />
			if (is_overlap_unlock(lkb)) {<br />
				wait_type = DLM_MSG_UNLOCK;<br />
				if (lkb->lkb_grmode == DLM_LOCK_IV)<br />
					stub_unlock_result = -ENOENT;<br />
			}</p>
<p>			log_debug(ls, &laquo;rwpre overlap %x %x %d %d %d&raquo;,<br />
				  lkb->lkb_id, lkb->lkb_flags, wait_type,<br />
				  stub_cancel_result, stub_unlock_result);<br />
		}</p>
<p>		switch (wait_type) {</p>
<p>		case DLM_MSG_REQUEST:<br />
			lkb->lkb_flags |= DLM_IFL_RESEND;<br />
			break;</p>
<p>		case DLM_MSG_CONVERT:<br />
			recover_convert_waiter(ls, lkb);<br />
			break;</p>
<p>		case DLM_MSG_UNLOCK:<br />
			hold_lkb(lkb);<br />
			ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;<br />
			ls->ls_stub_ms.m_result = stub_unlock_result;<br />
			ls->ls_stub_ms.m_flags = lkb->lkb_flags;<br />
			ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;<br />
			_receive_unlock_reply(lkb, &#038;ls->ls_stub_ms);<br />
			dlm_put_lkb(lkb);<br />
			break;</p>
<p>		case DLM_MSG_CANCEL:<br />
			hold_lkb(lkb);<br />
			ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY;<br />
			ls->ls_stub_ms.m_result = stub_cancel_result;<br />
			ls->ls_stub_ms.m_flags = lkb->lkb_flags;<br />
			ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;<br />
			_receive_cancel_reply(lkb, &#038;ls->ls_stub_ms);<br />
			dlm_put_lkb(lkb);<br />
			break;</p>
<p>		default:<br />
			log_error(ls, &laquo;invalid lkb wait_type %d %d&raquo;,<br />
				  lkb->lkb_wait_type, wait_type);<br />
		}<br />
		schedule();<br />
	}<br />
	mutex_unlock(&#038;ls->ls_waiters_mutex);<br />
}</p>
<p>static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int found = 0;</p>
<p>	mutex_lock(&#038;ls->ls_waiters_mutex);<br />
	list_for_each_entry(lkb, &#038;ls->ls_waiters, lkb_wait_reply) {<br />
		if (lkb->lkb_flags &#038; DLM_IFL_RESEND) {<br />
			hold_lkb(lkb);<br />
			found = 1;<br />
			break;<br />
		}<br />
	}<br />
	mutex_unlock(&#038;ls->ls_waiters_mutex);</p>
<p>	if (!found)<br />
		lkb = NULL;<br />
	return lkb;<br />
}</p>
<p>/* Deal with lookups and lkb&#8217;s marked RESEND from _pre.  We may now be the<br />
   master or dir-node for r.  Processing the lkb may result in it being placed<br />
   back on waiters. */</p>
<p>/* We do this after normal locking has been enabled and any saved messages<br />
   (in requestqueue) have been processed.  We should be confident that at<br />
   this point we won&#8217;t get or process a reply to any of these waiting<br />
   operations.  But, new ops may be coming in on the rsbs/locks here from<br />
   userspace or remotely. */</p>
<p>/* there may have been an overlap unlock/cancel prior to recovery or after<br />
   recovery.  if before, the lkb may still have a pos wait_count; if after, the<br />
   overlap flag would just have been set and nothing new sent.  we can be<br />
   confident here than any replies to either the initial op or overlap ops<br />
   prior to recovery have been received. */</p>
<p>int dlm_recover_waiters_post(struct dlm_ls *ls)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_rsb *r;<br />
	int error = 0, mstype, err, oc, ou;</p>
<p>	while (1) {<br />
		if (dlm_locking_stopped(ls)) {<br />
			log_debug(ls, &laquo;recover_waiters_post aborted&raquo;);<br />
			error = -EINTR;<br />
			break;<br />
		}</p>
<p>		lkb = find_resend_waiter(ls);<br />
		if (!lkb)<br />
			break;</p>
<p>		r = lkb->lkb_resource;<br />
		hold_rsb(r);<br />
		lock_rsb(r);</p>
<p>		mstype = lkb->lkb_wait_type;<br />
		oc = is_overlap_cancel(lkb);<br />
		ou = is_overlap_unlock(lkb);<br />
		err = 0;</p>
<p>		log_debug(ls, &laquo;recover_waiters_post %x type %d flags %x %s&raquo;,<br />
			  lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);</p>
<p>		/* At this point we assume that we won&#8217;t get a reply to any<br />
		   previous op or overlap op on this lock.  First, do a big<br />
		   remove_from_waiters() for all previous ops. */</p>
<p>		lkb->lkb_flags &#038;= ~DLM_IFL_RESEND;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_UNLOCK;<br />
		lkb->lkb_flags &#038;= ~DLM_IFL_OVERLAP_CANCEL;<br />
		lkb->lkb_wait_type = 0;<br />
		lkb->lkb_wait_count = 0;<br />
		mutex_lock(&#038;ls->ls_waiters_mutex);<br />
		list_del_init(&#038;lkb->lkb_wait_reply);<br />
		mutex_unlock(&#038;ls->ls_waiters_mutex);<br />
		unhold_lkb(lkb); /* for waiters list */</p>
<p>		if (oc || ou) {<br />
			/* do an unlock or cancel instead of resending */<br />
			switch (mstype) {<br />
			case DLM_MSG_LOOKUP:<br />
			case DLM_MSG_REQUEST:<br />
				queue_cast(r, lkb, ou ? -DLM_EUNLOCK :<br />
							-DLM_ECANCEL);<br />
				unhold_lkb(lkb); /* undoes create_lkb() */<br />
				break;<br />
			case DLM_MSG_CONVERT:<br />
				if (oc) {<br />
					queue_cast(r, lkb, -DLM_ECANCEL);<br />
				} else {<br />
					lkb->lkb_exflags |= DLM_LKF_FORCEUNLOCK;<br />
					_unlock_lock(r, lkb);<br />
				}<br />
				break;<br />
			default:<br />
				err = 1;<br />
			}<br />
		} else {<br />
			switch (mstype) {<br />
			case DLM_MSG_LOOKUP:<br />
			case DLM_MSG_REQUEST:<br />
				_request_lock(r, lkb);<br />
				if (is_master(r))<br />
					confirm_master(r, 0);<br />
				break;<br />
			case DLM_MSG_CONVERT:<br />
				_convert_lock(r, lkb);<br />
				break;<br />
			default:<br />
				err = 1;<br />
			}<br />
		}</p>
<p>		if (err)<br />
			log_error(ls, &laquo;recover_waiters_post %x %d %x %d %d&raquo;,<br />
			  	  lkb->lkb_id, mstype, lkb->lkb_flags, oc, ou);<br />
		unlock_rsb(r);<br />
		put_rsb(r);<br />
		dlm_put_lkb(lkb);<br />
	}</p>
<p>	return error;<br />
}</p>
<p>static void purge_queue(struct dlm_rsb *r, struct list_head *queue,<br />
			int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))<br />
{<br />
	struct dlm_ls *ls = r->res_ls;<br />
	struct dlm_lkb *lkb, *safe;</p>
<p>	list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {<br />
		if (test(ls, lkb)) {<br />
			rsb_set_flag(r, RSB_LOCKS_PURGED);<br />
			del_lkb(r, lkb);<br />
			/* this put should free the lkb */<br />
			if (!dlm_put_lkb(lkb))<br />
				log_error(ls, &laquo;purged lkb not released&raquo;);<br />
		}<br />
	}<br />
}</p>
<p>static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	return (is_master_copy(lkb) &#038;&#038; dlm_is_removed(ls, lkb->lkb_nodeid));<br />
}</p>
<p>static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	return is_master_copy(lkb);<br />
}</p>
<p>static void purge_dead_locks(struct dlm_rsb *r)<br />
{<br />
	purge_queue(r, &#038;r->res_grantqueue, &#038;purge_dead_test);<br />
	purge_queue(r, &#038;r->res_convertqueue, &#038;purge_dead_test);<br />
	purge_queue(r, &#038;r->res_waitqueue, &#038;purge_dead_test);<br />
}</p>
<p>void dlm_purge_mstcpy_locks(struct dlm_rsb *r)<br />
{<br />
	purge_queue(r, &#038;r->res_grantqueue, &#038;purge_mstcpy_test);<br />
	purge_queue(r, &#038;r->res_convertqueue, &#038;purge_mstcpy_test);<br />
	purge_queue(r, &#038;r->res_waitqueue, &#038;purge_mstcpy_test);<br />
}</p>
<p>/* Get rid of locks held by nodes that are gone. */</p>
<p>int dlm_purge_locks(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;</p>
<p>	log_debug(ls, &laquo;dlm_purge_locks&raquo;);</p>
<p>	down_write(&#038;ls->ls_root_sem);<br />
	list_for_each_entry(r, &#038;ls->ls_root_list, res_root_list) {<br />
		hold_rsb(r);<br />
		lock_rsb(r);<br />
		if (is_master(r))<br />
			purge_dead_locks(r);<br />
		unlock_rsb(r);<br />
		unhold_rsb(r);</p>
<p>		schedule();<br />
	}<br />
	up_write(&#038;ls->ls_root_sem);</p>
<p>	return 0;<br />
}</p>
<p>static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)<br />
{<br />
	struct dlm_rsb *r, *r_ret = NULL;</p>
<p>	spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	list_for_each_entry(r, &#038;ls->ls_rsbtbl[bucket].list, res_hashchain) {<br />
		if (!rsb_flag(r, RSB_LOCKS_PURGED))<br />
			continue;<br />
		hold_rsb(r);<br />
		rsb_clear_flag(r, RSB_LOCKS_PURGED);<br />
		r_ret = r;<br />
		break;<br />
	}<br />
	spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	return r_ret;<br />
}</p>
<p>void dlm_grant_after_purge(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	int bucket = 0;</p>
<p>	while (1) {<br />
		r = find_purged_rsb(ls, bucket);<br />
		if (!r) {<br />
			if (bucket == ls->ls_rsbtbl_size &#8211; 1)<br />
				break;<br />
			bucket++;<br />
			continue;<br />
		}<br />
		lock_rsb(r);<br />
		if (is_master(r)) {<br />
			grant_pending_locks(r);<br />
			confirm_master(r, 0);<br />
		}<br />
		unlock_rsb(r);<br />
		put_rsb(r);<br />
		schedule();<br />
	}<br />
}</p>
<p>static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,<br />
					 uint32_t remid)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	list_for_each_entry(lkb, head, lkb_statequeue) {<br />
		if (lkb->lkb_nodeid == nodeid &#038;&#038; lkb->lkb_remid == remid)<br />
			return lkb;<br />
	}<br />
	return NULL;<br />
}</p>
<p>static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,<br />
				    uint32_t remid)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	lkb = search_remid_list(&#038;r->res_grantqueue, nodeid, remid);<br />
	if (lkb)<br />
		return lkb;<br />
	lkb = search_remid_list(&#038;r->res_convertqueue, nodeid, remid);<br />
	if (lkb)<br />
		return lkb;<br />
	lkb = search_remid_list(&#038;r->res_waitqueue, nodeid, remid);<br />
	if (lkb)<br />
		return lkb;<br />
	return NULL;<br />
}</p>
<p>/* needs at least dlm_rcom + rcom_lock */<br />
static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,<br />
				  struct dlm_rsb *r, struct dlm_rcom *rc)<br />
{<br />
	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;</p>
<p>	lkb->lkb_nodeid = rc->rc_header.h_nodeid;<br />
	lkb->lkb_ownpid = le32_to_cpu(rl->rl_ownpid);<br />
	lkb->lkb_remid = le32_to_cpu(rl->rl_lkid);<br />
	lkb->lkb_exflags = le32_to_cpu(rl->rl_exflags);<br />
	lkb->lkb_flags = le32_to_cpu(rl->rl_flags) &#038; 0&#215;0000FFFF;<br />
	lkb->lkb_flags |= DLM_IFL_MSTCPY;<br />
	lkb->lkb_lvbseq = le32_to_cpu(rl->rl_lvbseq);<br />
	lkb->lkb_rqmode = rl->rl_rqmode;<br />
	lkb->lkb_grmode = rl->rl_grmode;<br />
	/* don&#8217;t set lkb_status because add_lkb wants to itself */</p>
<p>	lkb->lkb_bastfn = (rl->rl_asts &#038; AST_BAST) ? &#038;fake_bastfn : NULL;<br />
	lkb->lkb_astfn = (rl->rl_asts &#038; AST_COMP) ? &#038;fake_astfn : NULL;</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_VALBLK) {<br />
		int lvblen = rc->rc_header.h_length &#8211; sizeof(struct dlm_rcom) -<br />
			 sizeof(struct rcom_lock);<br />
		if (lvblen > ls->ls_lvblen)<br />
			return -EINVAL;<br />
		lkb->lkb_lvbptr = dlm_allocate_lvb(ls);<br />
		if (!lkb->lkb_lvbptr)<br />
			return -ENOMEM;<br />
		memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);<br />
	}</p>
<p>	/* Conversions between PR and CW (middle modes) need special handling.<br />
	   The real granted mode of these converting locks cannot be determined<br />
	   until all locks have been rebuilt on the rsb (recover_conversion) */</p>
<p>	if (rl->rl_wait_type == cpu_to_le16(DLM_MSG_CONVERT) &#038;&#038;<br />
	    middle_conversion(lkb)) {<br />
		rl->rl_status = DLM_LKSTS_CONVERT;<br />
		lkb->lkb_grmode = DLM_LOCK_IV;<br />
		rsb_set_flag(r, RSB_RECOVER_CONVERT);<br />
	}</p>
<p>	return 0;<br />
}</p>
<p>/* This lkb may have been recovered in a previous aborted recovery so we need<br />
   to check if the rsb already has an lkb with the given remote nodeid/lkid.<br />
   If so we just send back a standard reply.  If not, we create a new lkb with<br />
   the given values and send back our lkid.  We send back our lkid by sending<br />
   back the rcom_lock struct we got but with the remid field filled in. */</p>
<p>/* needs at least dlm_rcom + rcom_lock */<br />
int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)<br />
{<br />
	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;<br />
	struct dlm_rsb *r;<br />
	struct dlm_lkb *lkb;<br />
	int error;</p>
<p>	if (rl->rl_parent_lkid) {<br />
		error = -EOPNOTSUPP;<br />
		goto out;<br />
	}</p>
<p>	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),<br />
			 R_MASTER, &#038;r);<br />
	if (error)<br />
		goto out;</p>
<p>	lock_rsb(r);</p>
<p>	lkb = search_remid(r, rc->rc_header.h_nodeid, le32_to_cpu(rl->rl_lkid));<br />
	if (lkb) {<br />
		error = -EEXIST;<br />
		goto out_remid;<br />
	}</p>
<p>	error = create_lkb(ls, &#038;lkb);<br />
	if (error)<br />
		goto out_unlock;</p>
<p>	error = receive_rcom_lock_args(ls, lkb, r, rc);<br />
	if (error) {<br />
		__put_lkb(ls, lkb);<br />
		goto out_unlock;<br />
	}</p>
<p>	attach_lkb(r, lkb);<br />
	add_lkb(r, lkb, rl->rl_status);<br />
	error = 0;</p>
<p> out_remid:<br />
	/* this is the new value returned to the lock holder for<br />
	   saving in its process-copy lkb */<br />
	rl->rl_remid = cpu_to_le32(lkb->lkb_id);</p>
<p> out_unlock:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
 out:<br />
	if (error)<br />
		log_debug(ls, &laquo;recover_master_copy %d %x&raquo;, error,<br />
			  le32_to_cpu(rl->rl_lkid));<br />
	rl->rl_result = cpu_to_le32(error);<br />
	return error;<br />
}</p>
<p>/* needs at least dlm_rcom + rcom_lock */<br />
int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)<br />
{<br />
	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;<br />
	struct dlm_rsb *r;<br />
	struct dlm_lkb *lkb;<br />
	int error;</p>
<p>	error = find_lkb(ls, le32_to_cpu(rl->rl_lkid), &#038;lkb);<br />
	if (error) {<br />
		log_error(ls, &laquo;recover_process_copy no lkid %x&raquo;,<br />
				le32_to_cpu(rl->rl_lkid));<br />
		return error;<br />
	}</p>
<p>	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););</p>
<p>	error = le32_to_cpu(rl->rl_result);</p>
<p>	r = lkb->lkb_resource;<br />
	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	switch (error) {<br />
	case -EBADR:<br />
		/* There&#8217;s a chance the new master received our lock before<br />
		   dlm_recover_master_reply(), this wouldn&#8217;t happen if we did<br />
		   a barrier between recover_masters and recover_locks. */<br />
		log_debug(ls, &laquo;master copy not ready %x r %lx %s&raquo;, lkb->lkb_id,<br />
			  (unsigned long)r, r->res_name);<br />
		dlm_send_rcom_lock(r, lkb);<br />
		goto out;<br />
	case -EEXIST:<br />
		log_debug(ls, &laquo;master copy exists %x&raquo;, lkb->lkb_id);<br />
		/* fall through */<br />
	case 0:<br />
		lkb->lkb_remid = le32_to_cpu(rl->rl_remid);<br />
		break;<br />
	default:<br />
		log_error(ls, &laquo;dlm_recover_process_copy unknown error %d %x&raquo;,<br />
			  error, lkb->lkb_id);<br />
	}</p>
<p>	/* an ack for dlm_recover_locks() which waits for replies from<br />
	   all the locks it sends to new masters */<br />
	dlm_recovered_lock(r);<br />
 out:<br />
	unlock_rsb(r);<br />
	put_rsb(r);<br />
	dlm_put_lkb(lkb);</p>
<p>	return 0;<br />
}</p>
<p>int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,<br />
		     int mode, uint32_t flags, void *name, unsigned int namelen,<br />
		     unsigned long timeout_cs)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	int error;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = create_lkb(ls, &#038;lkb);<br />
	if (error) {<br />
		kfree(ua);<br />
		goto out;<br />
	}</p>
<p>	if (flags &#038; DLM_LKF_VALBLK) {<br />
		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);<br />
		if (!ua->lksb.sb_lvbptr) {<br />
			kfree(ua);<br />
			__put_lkb(ls, lkb);<br />
			error = -ENOMEM;<br />
			goto out;<br />
		}<br />
	}</p>
<p>	/* After ua is attached to lkb it will be freed by dlm_free_lkb().<br />
	   When DLM_IFL_USER is set, the dlm knows that this is a userspace<br />
	   lock and that lkb_astparam is the dlm_user_args structure. */</p>
<p>	error = set_lock_args(mode, &#038;ua->lksb, flags, namelen, timeout_cs,<br />
			      fake_astfn, ua, fake_bastfn, &#038;args);<br />
	lkb->lkb_flags |= DLM_IFL_USER;<br />
	ua->old_mode = DLM_LOCK_IV;</p>
<p>	if (error) {<br />
		__put_lkb(ls, lkb);<br />
		goto out;<br />
	}</p>
<p>	error = request_lock(ls, lkb, name, namelen, &#038;args);</p>
<p>	switch (error) {<br />
	case 0:<br />
		break;<br />
	case -EINPROGRESS:<br />
		error = 0;<br />
		break;<br />
	case -EAGAIN:<br />
		error = 0;<br />
		/* fall through */<br />
	default:<br />
		__put_lkb(ls, lkb);<br />
		goto out;<br />
	}</p>
<p>	/* add this new lkb to the per-process list of locks */<br />
	spin_lock(&#038;ua->proc->locks_spin);<br />
	hold_lkb(lkb);<br />
	list_add_tail(&#038;lkb->lkb_ownqueue, &#038;ua->proc->locks);<br />
	spin_unlock(&#038;ua->proc->locks_spin);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	return error;<br />
}</p>
<p>int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,<br />
		     int mode, uint32_t flags, uint32_t lkid, char *lvb_in,<br />
		     unsigned long timeout_cs)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	struct dlm_user_args *ua;<br />
	int error;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = find_lkb(ls, lkid, &#038;lkb);<br />
	if (error)<br />
		goto out;</p>
<p>	/* user can change the params on its lock when it converts it, or<br />
	   add an lvb that didn&#8217;t exist before */</p>
<p>	ua = lkb->lkb_ua;</p>
<p>	if (flags &#038; DLM_LKF_VALBLK &#038;&#038; !ua->lksb.sb_lvbptr) {<br />
		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);<br />
		if (!ua->lksb.sb_lvbptr) {<br />
			error = -ENOMEM;<br />
			goto out_put;<br />
		}<br />
	}<br />
	if (lvb_in &#038;&#038; ua->lksb.sb_lvbptr)<br />
		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);</p>
<p>	ua->xid = ua_tmp->xid;<br />
	ua->castparam = ua_tmp->castparam;<br />
	ua->castaddr = ua_tmp->castaddr;<br />
	ua->bastparam = ua_tmp->bastparam;<br />
	ua->bastaddr = ua_tmp->bastaddr;<br />
	ua->user_lksb = ua_tmp->user_lksb;<br />
	ua->old_mode = lkb->lkb_grmode;</p>
<p>	error = set_lock_args(mode, &#038;ua->lksb, flags, 0, timeout_cs,<br />
			      fake_astfn, ua, fake_bastfn, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	error = convert_lock(ls, lkb, &#038;args);</p>
<p>	if (error == -EINPROGRESS || error == -EAGAIN || error == -EDEADLK)<br />
		error = 0;<br />
 out_put:<br />
	dlm_put_lkb(lkb);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	kfree(ua_tmp);<br />
	return error;<br />
}</p>
<p>int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,<br />
		    uint32_t flags, uint32_t lkid, char *lvb_in)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	struct dlm_user_args *ua;<br />
	int error;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = find_lkb(ls, lkid, &#038;lkb);<br />
	if (error)<br />
		goto out;</p>
<p>	ua = lkb->lkb_ua;</p>
<p>	if (lvb_in &#038;&#038; ua->lksb.sb_lvbptr)<br />
		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);<br />
	if (ua_tmp->castparam)<br />
		ua->castparam = ua_tmp->castparam;<br />
	ua->user_lksb = ua_tmp->user_lksb;</p>
<p>	error = set_unlock_args(flags, ua, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	error = unlock_lock(ls, lkb, &#038;args);</p>
<p>	if (error == -DLM_EUNLOCK)<br />
		error = 0;<br />
	/* from validate_unlock_args() */<br />
	if (error == -EBUSY &#038;&#038; (flags &#038; DLM_LKF_FORCEUNLOCK))<br />
		error = 0;<br />
	if (error)<br />
		goto out_put;</p>
<p>	spin_lock(&#038;ua->proc->locks_spin);<br />
	/* dlm_user_add_ast() may have already taken lkb off the proc list */<br />
	if (!list_empty(&#038;lkb->lkb_ownqueue))<br />
		list_move(&#038;lkb->lkb_ownqueue, &#038;ua->proc->unlocking);<br />
	spin_unlock(&#038;ua->proc->locks_spin);<br />
 out_put:<br />
	dlm_put_lkb(lkb);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	kfree(ua_tmp);<br />
	return error;<br />
}</p>
<p>int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,<br />
		    uint32_t flags, uint32_t lkid)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	struct dlm_user_args *ua;<br />
	int error;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = find_lkb(ls, lkid, &#038;lkb);<br />
	if (error)<br />
		goto out;</p>
<p>	ua = lkb->lkb_ua;<br />
	if (ua_tmp->castparam)<br />
		ua->castparam = ua_tmp->castparam;<br />
	ua->user_lksb = ua_tmp->user_lksb;</p>
<p>	error = set_unlock_args(flags, ua, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	error = cancel_lock(ls, lkb, &#038;args);</p>
<p>	if (error == -DLM_ECANCEL)<br />
		error = 0;<br />
	/* from validate_unlock_args() */<br />
	if (error == -EBUSY)<br />
		error = 0;<br />
 out_put:<br />
	dlm_put_lkb(lkb);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	kfree(ua_tmp);<br />
	return error;<br />
}</p>
<p>int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	struct dlm_args args;<br />
	struct dlm_user_args *ua;<br />
	struct dlm_rsb *r;<br />
	int error;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	error = find_lkb(ls, lkid, &#038;lkb);<br />
	if (error)<br />
		goto out;</p>
<p>	ua = lkb->lkb_ua;</p>
<p>	error = set_unlock_args(flags, ua, &#038;args);<br />
	if (error)<br />
		goto out_put;</p>
<p>	/* same as cancel_lock(), but set DEADLOCK_CANCEL after lock_rsb */</p>
<p>	r = lkb->lkb_resource;<br />
	hold_rsb(r);<br />
	lock_rsb(r);</p>
<p>	error = validate_unlock_args(lkb, &#038;args);<br />
	if (error)<br />
		goto out_r;<br />
	lkb->lkb_flags |= DLM_IFL_DEADLOCK_CANCEL;</p>
<p>	error = _cancel_lock(r, lkb);<br />
 out_r:<br />
	unlock_rsb(r);<br />
	put_rsb(r);</p>
<p>	if (error == -DLM_ECANCEL)<br />
		error = 0;<br />
	/* from validate_unlock_args() */<br />
	if (error == -EBUSY)<br />
		error = 0;<br />
 out_put:<br />
	dlm_put_lkb(lkb);<br />
 out:<br />
	dlm_unlock_recovery(ls);<br />
	return error;<br />
}</p>
<p>/* lkb&#8217;s that are removed from the waiters list by revert are just left on the<br />
   orphans list with the granted orphan locks, to be freed by purge */</p>
<p>static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_args args;<br />
	int error;</p>
<p>	hold_lkb(lkb);<br />
	mutex_lock(&#038;ls->ls_orphans_mutex);<br />
	list_add_tail(&#038;lkb->lkb_ownqueue, &#038;ls->ls_orphans);<br />
	mutex_unlock(&#038;ls->ls_orphans_mutex);</p>
<p>	set_unlock_args(0, lkb->lkb_ua, &#038;args);</p>
<p>	error = cancel_lock(ls, lkb, &#038;args);<br />
	if (error == -DLM_ECANCEL)<br />
		error = 0;<br />
	return error;<br />
}</p>
<p>/* The force flag allows the unlock to go ahead even if the lkb isn&#8217;t granted.<br />
   Regardless of what rsb queue the lock is on, it&#8217;s removed and freed. */</p>
<p>static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)<br />
{<br />
	struct dlm_args args;<br />
	int error;</p>
<p>	set_unlock_args(DLM_LKF_FORCEUNLOCK, lkb->lkb_ua, &#038;args);</p>
<p>	error = unlock_lock(ls, lkb, &#038;args);<br />
	if (error == -DLM_EUNLOCK)<br />
		error = 0;<br />
	return error;<br />
}</p>
<p>/* We have to release clear_proc_locks mutex before calling unlock_proc_lock()<br />
   (which does lock_rsb) due to deadlock with receiving a message that does<br />
   lock_rsb followed by dlm_user_add_ast() */</p>
<p>static struct dlm_lkb *del_proc_lock(struct dlm_ls *ls,<br />
				     struct dlm_user_proc *proc)<br />
{<br />
	struct dlm_lkb *lkb = NULL;</p>
<p>	mutex_lock(&#038;ls->ls_clear_proc_locks);<br />
	if (list_empty(&#038;proc->locks))<br />
		goto out;</p>
<p>	lkb = list_entry(proc->locks.next, struct dlm_lkb, lkb_ownqueue);<br />
	list_del_init(&#038;lkb->lkb_ownqueue);</p>
<p>	if (lkb->lkb_exflags &#038; DLM_LKF_PERSISTENT)<br />
		lkb->lkb_flags |= DLM_IFL_ORPHAN;<br />
	else<br />
		lkb->lkb_flags |= DLM_IFL_DEAD;<br />
 out:<br />
	mutex_unlock(&#038;ls->ls_clear_proc_locks);<br />
	return lkb;<br />
}</p>
<p>/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which<br />
   1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,<br />
   which we clear here. */</p>
<p>/* proc CLOSING flag is set so no more device_reads should look at proc->asts<br />
   list, and no more device_writes should add lkb&#8217;s to proc->locks list; so we<br />
   shouldn&#8217;t need to take asts_spin or locks_spin here.  this assumes that<br />
   device reads/writes/closes are serialized &#8212; FIXME: we may need to serialize<br />
   them ourself. */</p>
<p>void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)<br />
{<br />
	struct dlm_lkb *lkb, *safe;</p>
<p>	dlm_lock_recovery(ls);</p>
<p>	while (1) {<br />
		lkb = del_proc_lock(ls, proc);<br />
		if (!lkb)<br />
			break;<br />
		del_timeout(lkb);<br />
		if (lkb->lkb_exflags &#038; DLM_LKF_PERSISTENT)<br />
			orphan_proc_lock(ls, lkb);<br />
		else<br />
			unlock_proc_lock(ls, lkb);</p>
<p>		/* this removes the reference for the proc->locks list<br />
		   added by dlm_user_request, it may result in the lkb<br />
		   being freed */</p>
<p>		dlm_put_lkb(lkb);<br />
	}</p>
<p>	mutex_lock(&#038;ls->ls_clear_proc_locks);</p>
<p>	/* in-progress unlocks */<br />
	list_for_each_entry_safe(lkb, safe, &#038;proc->unlocking, lkb_ownqueue) {<br />
		list_del_init(&#038;lkb->lkb_ownqueue);<br />
		lkb->lkb_flags |= DLM_IFL_DEAD;<br />
		dlm_put_lkb(lkb);<br />
	}</p>
<p>	list_for_each_entry_safe(lkb, safe, &#038;proc->asts, lkb_astqueue) {<br />
		lkb->lkb_ast_type = 0;<br />
		list_del(&#038;lkb->lkb_astqueue);<br />
		dlm_put_lkb(lkb);<br />
	}</p>
<p>	mutex_unlock(&#038;ls->ls_clear_proc_locks);<br />
	dlm_unlock_recovery(ls);<br />
}</p>
<p>static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)<br />
{<br />
	struct dlm_lkb *lkb, *safe;</p>
<p>	while (1) {<br />
		lkb = NULL;<br />
		spin_lock(&#038;proc->locks_spin);<br />
		if (!list_empty(&#038;proc->locks)) {<br />
			lkb = list_entry(proc->locks.next, struct dlm_lkb,<br />
					 lkb_ownqueue);<br />
			list_del_init(&#038;lkb->lkb_ownqueue);<br />
		}<br />
		spin_unlock(&#038;proc->locks_spin);</p>
<p>		if (!lkb)<br />
			break;</p>
<p>		lkb->lkb_flags |= DLM_IFL_DEAD;<br />
		unlock_proc_lock(ls, lkb);<br />
		dlm_put_lkb(lkb); /* ref from proc->locks list */<br />
	}</p>
<p>	spin_lock(&#038;proc->locks_spin);<br />
	list_for_each_entry_safe(lkb, safe, &#038;proc->unlocking, lkb_ownqueue) {<br />
		list_del_init(&#038;lkb->lkb_ownqueue);<br />
		lkb->lkb_flags |= DLM_IFL_DEAD;<br />
		dlm_put_lkb(lkb);<br />
	}<br />
	spin_unlock(&#038;proc->locks_spin);</p>
<p>	spin_lock(&#038;proc->asts_spin);<br />
	list_for_each_entry_safe(lkb, safe, &#038;proc->asts, lkb_astqueue) {<br />
		list_del(&#038;lkb->lkb_astqueue);<br />
		dlm_put_lkb(lkb);<br />
	}<br />
	spin_unlock(&#038;proc->asts_spin);<br />
}</p>
<p>/* pid of 0 means purge all orphans */</p>
<p>static void do_purge(struct dlm_ls *ls, int nodeid, int pid)<br />
{<br />
	struct dlm_lkb *lkb, *safe;</p>
<p>	mutex_lock(&#038;ls->ls_orphans_mutex);<br />
	list_for_each_entry_safe(lkb, safe, &#038;ls->ls_orphans, lkb_ownqueue) {<br />
		if (pid &#038;&#038; lkb->lkb_ownpid != pid)<br />
			continue;<br />
		unlock_proc_lock(ls, lkb);<br />
		list_del_init(&#038;lkb->lkb_ownqueue);<br />
		dlm_put_lkb(lkb);<br />
	}<br />
	mutex_unlock(&#038;ls->ls_orphans_mutex);<br />
}</p>
<p>static int send_purge(struct dlm_ls *ls, int nodeid, int pid)<br />
{<br />
	struct dlm_message *ms;<br />
	struct dlm_mhandle *mh;<br />
	int error;</p>
<p>	error = _create_message(ls, sizeof(struct dlm_message), nodeid,<br />
				DLM_MSG_PURGE, &#038;ms, &#038;mh);<br />
	if (error)<br />
		return error;<br />
	ms->m_nodeid = nodeid;<br />
	ms->m_pid = pid;</p>
<p>	return send_message(mh, ms);<br />
}</p>
<p>int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,<br />
		   int nodeid, int pid)<br />
{<br />
	int error = 0;</p>
<p>	if (nodeid != dlm_our_nodeid()) {<br />
		error = send_purge(ls, nodeid, pid);<br />
	} else {<br />
		dlm_lock_recovery(ls);<br />
		if (pid == current->pid)<br />
			purge_proc_locks(ls, proc);<br />
		else<br />
			do_purge(ls, nodeid, pid);<br />
		dlm_unlock_recovery(ls);<br />
	}<br />
	return error;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/lock-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kconfig</title>
		<link>http://lynyrd.ru/kconfig-13</link>
		<comments>http://lynyrd.ru/kconfig-13#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:49:42 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1031</guid>
		<description><![CDATA[menuconfig DLM
	tristate &#171;Distributed Lock Manager (DLM)&#187;
	depends on EXPERIMENTAL &#038;&#038; INET
	depends on SYSFS &#038;&#038; (IPV6 &#124;&#124; IPV6=n)
	select CONFIGFS_FS
	select IP_SCTP
	help
	A general purpose distributed lock manager for kernel or userspace
	applications.
config DLM_DEBUG
	bool &#171;DLM debugging&#187;
	depends on DLM
	help
	Under the debugfs mount point, the name of each lockspace will
	appear as a file in the &#171;dlm&#187; directory.  The output is the
	list of ]]></description>
			<content:encoded><![CDATA[<p>menuconfig DLM<br />
	tristate &laquo;Distributed Lock Manager (DLM)&raquo;<span id="more-1031"></span><br />
	depends on EXPERIMENTAL &#038;&#038; INET<br />
	depends on SYSFS &#038;&#038; (IPV6 || IPV6=n)<br />
	select CONFIGFS_FS<br />
	select IP_SCTP<br />
	help<br />
	A general purpose distributed lock manager for kernel or userspace<br />
	applications.</p>
<p>config DLM_DEBUG<br />
	bool &laquo;DLM debugging&raquo;<br />
	depends on DLM<br />
	help<br />
	Under the debugfs mount point, the name of each lockspace will<br />
	appear as a file in the &laquo;dlm&raquo; directory.  The output is the<br />
	list of resource and locks the local node knows about.</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/kconfig-13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dlm_internal.h</title>
		<link>http://lynyrd.ru/dlm_internal-h</link>
		<comments>http://lynyrd.ru/dlm_internal-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:49:26 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1029</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2008 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1029"></span><br />
**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __DLM_INTERNAL_DOT_H__<br />
#define __DLM_INTERNAL_DOT_H__</p>
<p>/*<br />
 * This is the main header file to be included in each DLM source file.<br />
 */</p>
<p>#include
<linux/module.h>
#include
<linux/slab.h>
#include
<linux/sched.h>
#include
<linux/types.h>
#include
<linux/ctype.h>
#include
<linux/spinlock.h>
#include
<linux/vmalloc.h>
#include
<linux/list.h>
#include
<linux/errno.h>
#include
<linux/random.h>
#include
<linux/delay.h>
#include
<linux/socket.h>
#include
<linux/kthread.h>
#include
<linux/kobject.h>
#include
<linux/kref.h>
#include
<linux/kernel.h>
#include
<linux/jhash.h>
#include
<linux/miscdevice.h>
#include
<linux/mutex.h>
#include <asm/uaccess.h></p>
<p>#include
<linux/dlm.h>
#include &laquo;config.h&raquo;</p>
<p>/* Size of the temp buffer midcomms allocates on the stack.<br />
   We try to make this large enough so most messages fit.<br />
   FIXME: should sctp make this unnecessary? */</p>
<p>#define DLM_INBUF_LEN		148</p>
<p>struct dlm_ls;<br />
struct dlm_lkb;<br />
struct dlm_rsb;<br />
struct dlm_member;<br />
struct dlm_lkbtable;<br />
struct dlm_rsbtable;<br />
struct dlm_dirtable;<br />
struct dlm_direntry;<br />
struct dlm_recover;<br />
struct dlm_header;<br />
struct dlm_message;<br />
struct dlm_rcom;<br />
struct dlm_mhandle;</p>
<p>#define log_print(fmt, args&#8230;) \<br />
	printk(KERN_ERR &laquo;dlm: &laquo;fmt&raquo;\n&raquo; , ##args)<br />
#define log_error(ls, fmt, args&#8230;) \<br />
	printk(KERN_ERR &laquo;dlm: %s: &raquo; fmt &laquo;\n&raquo;, (ls)->ls_name , ##args)</p>
<p>#define log_debug(ls, fmt, args&#8230;) \<br />
do { \<br />
	if (dlm_config.ci_log_debug) \<br />
		printk(KERN_DEBUG &laquo;dlm: %s: &raquo; fmt &laquo;\n&raquo;, \<br />
		       (ls)->ls_name , ##args); \<br />
} while (0)</p>
<p>#define DLM_ASSERT(x, do) \<br />
{ \<br />
  if (!(x)) \<br />
  { \<br />
    printk(KERN_ERR &laquo;\nDLM:  Assertion failed on line %d of file %s\n&raquo; \<br />
               &laquo;DLM:  assertion:  \&raquo;%s\&raquo;\n&raquo; \<br />
               &laquo;DLM:  time = %lu\n&raquo;, \<br />
               __LINE__, __FILE__, #x, jiffies); \<br />
    {do} \<br />
    printk(&raquo;\n&raquo;); \<br />
    BUG(); \<br />
    panic(&raquo;DLM:  Record message above and reboot.\n&raquo;); \<br />
  } \<br />
}</p>
<p>struct dlm_direntry {<br />
	struct list_head	list;<br />
	uint32_t		master_nodeid;<br />
	uint16_t		length;<br />
	char			name[1];<br />
};</p>
<p>struct dlm_dirtable {<br />
	struct list_head	list;<br />
	spinlock_t		lock;<br />
};</p>
<p>struct dlm_rsbtable {<br />
	struct list_head	list;<br />
	struct list_head	toss;<br />
	spinlock_t		lock;<br />
};</p>
<p>struct dlm_lkbtable {<br />
	struct list_head	list;<br />
	rwlock_t		lock;<br />
	uint16_t		counter;<br />
};</p>
<p>/*<br />
 * Lockspace member (per node in a ls)<br />
 */</p>
<p>struct dlm_member {<br />
	struct list_head	list;<br />
	int			nodeid;<br />
	int			weight;<br />
};</p>
<p>/*<br />
 * Save and manage recovery state for a lockspace.<br />
 */</p>
<p>struct dlm_recover {<br />
	struct list_head	list;<br />
	int			*nodeids;   /* nodeids of all members */<br />
	int			node_count;<br />
	int			*new;       /* nodeids of new members */<br />
	int			new_count;<br />
	uint64_t		seq;<br />
};</p>
<p>/*<br />
 * Pass input args to second stage locking function.<br />
 */</p>
<p>struct dlm_args {<br />
	uint32_t		flags;<br />
	void			(*astfn) (void *astparam);<br />
	void			*astparam;<br />
	void			(*bastfn) (void *astparam, int mode);<br />
	int			mode;<br />
	struct dlm_lksb		*lksb;<br />
	unsigned long		timeout;<br />
};</p>
<p>/*<br />
 * Lock block<br />
 *<br />
 * A lock can be one of three types:<br />
 *<br />
 * local copy      lock is mastered locally<br />
 *                 (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set)<br />
 * process copy    lock is mastered on a remote node<br />
 *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set)<br />
 * master copy     master node&#8217;s copy of a lock owned by remote node<br />
 *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set)<br />
 *<br />
 * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or<br />
 * dlm_unlock.  The dlm does not modify these or use any private flags in<br />
 * this field; it only contains DLM_LKF_ flags from dlm.h.  These flags<br />
 * are sent as-is to the remote master when the lock is remote.<br />
 *<br />
 * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h.<br />
 * Some internal flags are shared between the master and process nodes;<br />
 * these shared flags are kept in the lower two bytes.  One of these<br />
 * flags set on the master copy will be propagated to the process copy<br />
 * and v.v.  Other internal flags are private to the master or process<br />
 * node (e.g. DLM_IFL_MSTCPY).  These are kept in the high two bytes.<br />
 *<br />
 * lkb_sbflags: status block flags.  These flags are copied directly into<br />
 * the caller&#8217;s lksb.sb_flags prior to the dlm_lock/dlm_unlock completion<br />
 * ast.  All defined in dlm.h with DLM_SBF_ prefix.<br />
 *<br />
 * lkb_status: the lock status indicates which rsb queue the lock is<br />
 * on, grant, convert, or wait.  DLM_LKSTS_ WAITING/GRANTED/CONVERT<br />
 *<br />
 * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a<br />
 * reply is needed.  Only set when the lkb is on the lockspace waiters<br />
 * list awaiting a reply from a remote node.<br />
 *<br />
 * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb<br />
 * is a master copy, nodeid specifies the remote lock holder, when the<br />
 * lkb is a process copy, the nodeid specifies the lock master.<br />
 */</p>
<p>/* lkb_ast_type */</p>
<p>#define AST_COMP		1<br />
#define AST_BAST		2</p>
<p>/* lkb_status */</p>
<p>#define DLM_LKSTS_WAITING	1<br />
#define DLM_LKSTS_GRANTED	2<br />
#define DLM_LKSTS_CONVERT	3</p>
<p>/* lkb_flags */</p>
<p>#define DLM_IFL_MSTCPY		0&#215;00010000<br />
#define DLM_IFL_RESEND		0&#215;00020000<br />
#define DLM_IFL_DEAD		0&#215;00040000<br />
#define DLM_IFL_OVERLAP_UNLOCK  0&#215;00080000<br />
#define DLM_IFL_OVERLAP_CANCEL  0&#215;00100000<br />
#define DLM_IFL_ENDOFLIFE	0&#215;00200000<br />
#define DLM_IFL_WATCH_TIMEWARN	0&#215;00400000<br />
#define DLM_IFL_TIMEOUT_CANCEL	0&#215;00800000<br />
#define DLM_IFL_DEADLOCK_CANCEL	0&#215;01000000<br />
#define DLM_IFL_USER		0&#215;00000001<br />
#define DLM_IFL_ORPHAN		0&#215;00000002</p>
<p>struct dlm_lkb {<br />
	struct dlm_rsb		*lkb_resource;	/* the rsb */<br />
	struct kref		lkb_ref;<br />
	int			lkb_nodeid;	/* copied from rsb */<br />
	int			lkb_ownpid;	/* pid of lock owner */<br />
	uint32_t		lkb_id;		/* our lock ID */<br />
	uint32_t		lkb_remid;	/* lock ID on remote partner */<br />
	uint32_t		lkb_exflags;	/* external flags from caller */<br />
	uint32_t		lkb_sbflags;	/* lksb flags */<br />
	uint32_t		lkb_flags;	/* internal flags */<br />
	uint32_t		lkb_lvbseq;	/* lvb sequence number */</p>
<p>	int8_t			lkb_status;     /* granted, waiting, convert */<br />
	int8_t			lkb_rqmode;	/* requested lock mode */<br />
	int8_t			lkb_grmode;	/* granted lock mode */<br />
	int8_t			lkb_bastmode;	/* requested mode */<br />
	int8_t			lkb_highbast;	/* highest mode bast sent for */<br />
	int8_t			lkb_wait_type;	/* type of reply waiting for */<br />
	int8_t			lkb_wait_count;<br />
	int8_t			lkb_ast_type;	/* type of ast queued for */</p>
<p>	struct list_head	lkb_idtbl_list;	/* lockspace lkbtbl */<br />
	struct list_head	lkb_statequeue;	/* rsb g/c/w list */<br />
	struct list_head	lkb_rsb_lookup;	/* waiting for rsb lookup */<br />
	struct list_head	lkb_wait_reply;	/* waiting for remote reply */<br />
	struct list_head	lkb_astqueue;	/* need ast to be sent */<br />
	struct list_head	lkb_ownqueue;	/* list of locks for a process */<br />
	struct list_head	lkb_time_list;<br />
	ktime_t			lkb_time_bast;	/* for debugging */<br />
	ktime_t			lkb_timestamp;<br />
	unsigned long		lkb_timeout_cs;</p>
<p>	char			*lkb_lvbptr;<br />
	struct dlm_lksb		*lkb_lksb;      /* caller&#8217;s status block */<br />
	void			(*lkb_astfn) (void *astparam);<br />
	void			(*lkb_bastfn) (void *astparam, int mode);<br />
	union {<br />
		void			*lkb_astparam;	/* caller&#8217;s ast arg */<br />
		struct dlm_user_args	*lkb_ua;<br />
	};<br />
};</p>
<p>struct dlm_rsb {<br />
	struct dlm_ls		*res_ls;	/* the lockspace */<br />
	struct kref		res_ref;<br />
	struct mutex		res_mutex;<br />
	unsigned long		res_flags;<br />
	int			res_length;	/* length of rsb name */<br />
	int			res_nodeid;<br />
	uint32_t                res_lvbseq;<br />
	uint32_t		res_hash;<br />
	uint32_t		res_bucket;	/* rsbtbl */<br />
	unsigned long		res_toss_time;<br />
	uint32_t		res_first_lkid;<br />
	struct list_head	res_lookup;	/* lkbs waiting on first */<br />
	struct list_head	res_hashchain;	/* rsbtbl */<br />
	struct list_head	res_grantqueue;<br />
	struct list_head	res_convertqueue;<br />
	struct list_head	res_waitqueue;</p>
<p>	struct list_head	res_root_list;	    /* used for recovery */<br />
	struct list_head	res_recover_list;   /* used for recovery */<br />
	int			res_recover_locks_count;</p>
<p>	char			*res_lvbptr;<br />
	char			res_name[1];<br />
};</p>
<p>/* find_rsb() flags */</p>
<p>#define R_MASTER		1	/* only return rsb if it&#8217;s a master */<br />
#define R_CREATE		2	/* create/add rsb if not found */</p>
<p>/* rsb_flags */</p>
<p>enum rsb_flags {<br />
	RSB_MASTER_UNCERTAIN,<br />
	RSB_VALNOTVALID,<br />
	RSB_VALNOTVALID_PREV,<br />
	RSB_NEW_MASTER,<br />
	RSB_NEW_MASTER2,<br />
	RSB_RECOVER_CONVERT,<br />
	RSB_LOCKS_PURGED,<br />
};</p>
<p>static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)<br />
{<br />
	__set_bit(flag, &#038;r->res_flags);<br />
}</p>
<p>static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag)<br />
{<br />
	__clear_bit(flag, &#038;r->res_flags);<br />
}</p>
<p>static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)<br />
{<br />
	return test_bit(flag, &#038;r->res_flags);<br />
}</p>
<p>/* dlm_header is first element of all structs sent between nodes */</p>
<p>#define DLM_HEADER_MAJOR	0&#215;00030000<br />
#define DLM_HEADER_MINOR	0&#215;00000000</p>
<p>#define DLM_MSG			1<br />
#define DLM_RCOM		2</p>
<p>struct dlm_header {<br />
	uint32_t		h_version;<br />
	uint32_t		h_lockspace;<br />
	uint32_t		h_nodeid;	/* nodeid of sender */<br />
	uint16_t		h_length;<br />
	uint8_t			h_cmd;		/* DLM_MSG, DLM_RCOM */<br />
	uint8_t			h_pad;<br />
};</p>
<p>#define DLM_MSG_REQUEST		1<br />
#define DLM_MSG_CONVERT		2<br />
#define DLM_MSG_UNLOCK		3<br />
#define DLM_MSG_CANCEL		4<br />
#define DLM_MSG_REQUEST_REPLY	5<br />
#define DLM_MSG_CONVERT_REPLY	6<br />
#define DLM_MSG_UNLOCK_REPLY	7<br />
#define DLM_MSG_CANCEL_REPLY	8<br />
#define DLM_MSG_GRANT		9<br />
#define DLM_MSG_BAST		10<br />
#define DLM_MSG_LOOKUP		11<br />
#define DLM_MSG_REMOVE		12<br />
#define DLM_MSG_LOOKUP_REPLY	13<br />
#define DLM_MSG_PURGE		14</p>
<p>struct dlm_message {<br />
	struct dlm_header	m_header;<br />
	uint32_t		m_type;		/* DLM_MSG_ */<br />
	uint32_t		m_nodeid;<br />
	uint32_t		m_pid;<br />
	uint32_t		m_lkid;		/* lkid on sender */<br />
	uint32_t		m_remid;	/* lkid on receiver */<br />
	uint32_t		m_parent_lkid;<br />
	uint32_t		m_parent_remid;<br />
	uint32_t		m_exflags;<br />
	uint32_t		m_sbflags;<br />
	uint32_t		m_flags;<br />
	uint32_t		m_lvbseq;<br />
	uint32_t		m_hash;<br />
	int			m_status;<br />
	int			m_grmode;<br />
	int			m_rqmode;<br />
	int			m_bastmode;<br />
	int			m_asts;<br />
	int			m_result;	/* 0 or -EXXX */<br />
	char			m_extra[0];	/* name or lvb */<br />
};</p>
<p>#define DLM_RS_NODES		0&#215;00000001<br />
#define DLM_RS_NODES_ALL	0&#215;00000002<br />
#define DLM_RS_DIR		0&#215;00000004<br />
#define DLM_RS_DIR_ALL		0&#215;00000008<br />
#define DLM_RS_LOCKS		0&#215;00000010<br />
#define DLM_RS_LOCKS_ALL	0&#215;00000020<br />
#define DLM_RS_DONE		0&#215;00000040<br />
#define DLM_RS_DONE_ALL		0&#215;00000080</p>
<p>#define DLM_RCOM_STATUS		1<br />
#define DLM_RCOM_NAMES		2<br />
#define DLM_RCOM_LOOKUP		3<br />
#define DLM_RCOM_LOCK		4<br />
#define DLM_RCOM_STATUS_REPLY	5<br />
#define DLM_RCOM_NAMES_REPLY	6<br />
#define DLM_RCOM_LOOKUP_REPLY	7<br />
#define DLM_RCOM_LOCK_REPLY	8</p>
<p>struct dlm_rcom {<br />
	struct dlm_header	rc_header;<br />
	uint32_t		rc_type;	/* DLM_RCOM_ */<br />
	int			rc_result;	/* multi-purpose */<br />
	uint64_t		rc_id;		/* match reply with request */<br />
	uint64_t		rc_seq;		/* sender&#8217;s ls_recover_seq */<br />
	uint64_t		rc_seq_reply;	/* remote ls_recover_seq */<br />
	char			rc_buf[0];<br />
};</p>
<p>union dlm_packet {<br />
	struct dlm_header	header;		/* common to other two */<br />
	struct dlm_message	message;<br />
	struct dlm_rcom		rcom;<br />
};</p>
<p>struct rcom_config {<br />
	__le32			rf_lvblen;<br />
	__le32			rf_lsflags;<br />
	__le64			rf_unused;<br />
};</p>
<p>struct rcom_lock {<br />
	__le32			rl_ownpid;<br />
	__le32			rl_lkid;<br />
	__le32			rl_remid;<br />
	__le32			rl_parent_lkid;<br />
	__le32			rl_parent_remid;<br />
	__le32			rl_exflags;<br />
	__le32			rl_flags;<br />
	__le32			rl_lvbseq;<br />
	__le32			rl_result;<br />
	int8_t			rl_rqmode;<br />
	int8_t			rl_grmode;<br />
	int8_t			rl_status;<br />
	int8_t			rl_asts;<br />
	__le16			rl_wait_type;<br />
	__le16			rl_namelen;<br />
	char			rl_name[DLM_RESNAME_MAXLEN];<br />
	char			rl_lvb[0];<br />
};</p>
<p>struct dlm_ls {<br />
	struct list_head	ls_list;	/* list of lockspaces */<br />
	dlm_lockspace_t		*ls_local_handle;<br />
	uint32_t		ls_global_id;	/* global unique lockspace ID */<br />
	uint32_t		ls_exflags;<br />
	int			ls_lvblen;<br />
	int			ls_count;	/* refcount of processes in<br />
						   the dlm using this ls */<br />
	int			ls_create_count; /* create/release refcount */<br />
	unsigned long		ls_flags;	/* LSFL_ */<br />
	unsigned long		ls_scan_time;<br />
	struct kobject		ls_kobj;</p>
<p>	struct dlm_rsbtable	*ls_rsbtbl;<br />
	uint32_t		ls_rsbtbl_size;</p>
<p>	struct dlm_lkbtable	*ls_lkbtbl;<br />
	uint32_t		ls_lkbtbl_size;</p>
<p>	struct dlm_dirtable	*ls_dirtbl;<br />
	uint32_t		ls_dirtbl_size;</p>
<p>	struct mutex		ls_waiters_mutex;<br />
	struct list_head	ls_waiters;	/* lkbs needing a reply */</p>
<p>	struct mutex		ls_orphans_mutex;<br />
	struct list_head	ls_orphans;</p>
<p>	struct mutex		ls_timeout_mutex;<br />
	struct list_head	ls_timeout;</p>
<p>	struct list_head	ls_nodes;	/* current nodes in ls */<br />
	struct list_head	ls_nodes_gone;	/* dead node list, recovery */<br />
	int			ls_num_nodes;	/* number of nodes in ls */<br />
	int			ls_low_nodeid;<br />
	int			ls_total_weight;<br />
	int			*ls_node_array;<br />
	gfp_t			ls_allocation;</p>
<p>	struct dlm_rsb		ls_stub_rsb;	/* for returning errors */<br />
	struct dlm_lkb		ls_stub_lkb;	/* for returning errors */<br />
	struct dlm_message	ls_stub_ms;	/* for faking a reply */</p>
<p>	struct dentry		*ls_debug_rsb_dentry; /* debugfs */<br />
	struct dentry		*ls_debug_waiters_dentry; /* debugfs */<br />
	struct dentry		*ls_debug_locks_dentry; /* debugfs */<br />
	struct dentry		*ls_debug_all_dentry; /* debugfs */</p>
<p>	wait_queue_head_t	ls_uevent_wait;	/* user part of join/leave */<br />
	int			ls_uevent_result;<br />
	struct completion	ls_members_done;<br />
	int			ls_members_result;</p>
<p>	struct miscdevice       ls_device;</p>
<p>	/* recovery related */</p>
<p>	struct timer_list	ls_timer;<br />
	struct task_struct	*ls_recoverd_task;<br />
	struct mutex		ls_recoverd_active;<br />
	spinlock_t		ls_recover_lock;<br />
	unsigned long		ls_recover_begin; /* jiffies timestamp */<br />
	uint32_t		ls_recover_status; /* DLM_RS_ */<br />
	uint64_t		ls_recover_seq;<br />
	struct dlm_recover	*ls_recover_args;<br />
	struct rw_semaphore	ls_in_recovery;	/* block local requests */<br />
	struct rw_semaphore	ls_recv_active;	/* block dlm_recv */<br />
	struct list_head	ls_requestqueue;/* queue remote requests */<br />
	struct mutex		ls_requestqueue_mutex;<br />
	struct dlm_rcom		*ls_recover_buf;<br />
	int			ls_recover_nodeid; /* for debugging */<br />
	uint64_t		ls_rcom_seq;<br />
	spinlock_t		ls_rcom_spin;<br />
	struct list_head	ls_recover_list;<br />
	spinlock_t		ls_recover_list_lock;<br />
	int			ls_recover_list_count;<br />
	wait_queue_head_t	ls_wait_general;<br />
	struct mutex		ls_clear_proc_locks;</p>
<p>	struct list_head	ls_root_list;	/* root resources */<br />
	struct rw_semaphore	ls_root_sem;	/* protect root_list */</p>
<p>	int			ls_namelen;<br />
	char			ls_name[1];<br />
};</p>
<p>#define LSFL_WORK		0<br />
#define LSFL_RUNNING		1<br />
#define LSFL_RECOVERY_STOP	2<br />
#define LSFL_RCOM_READY		3<br />
#define LSFL_RCOM_WAIT		4<br />
#define LSFL_UEVENT_WAIT	5<br />
#define LSFL_TIMEWARN		6</p>
<p>/* much of this is just saving user space pointers associated with the<br />
   lock that we pass back to the user lib with an ast */</p>
<p>struct dlm_user_args {<br />
	struct dlm_user_proc	*proc; /* each process that opens the lockspace<br />
					  device has private data<br />
					  (dlm_user_proc) on the struct file,<br />
					  the process&#8217;s locks point back to it*/<br />
	struct dlm_lksb		lksb;<br />
	int			old_mode;<br />
	int			update_user_lvb;<br />
	struct dlm_lksb __user	*user_lksb;<br />
	void __user		*castparam;<br />
	void __user		*castaddr;<br />
	void __user		*bastparam;<br />
	void __user		*bastaddr;<br />
	uint64_t		xid;<br />
};</p>
<p>#define DLM_PROC_FLAGS_CLOSING 1<br />
#define DLM_PROC_FLAGS_COMPAT  2</p>
<p>/* locks list is kept so we can remove all a process&#8217;s locks when it<br />
   exits (or orphan those that are persistent) */</p>
<p>struct dlm_user_proc {<br />
	dlm_lockspace_t		*lockspace;<br />
	unsigned long		flags; /* DLM_PROC_FLAGS */<br />
	struct list_head	asts;<br />
	spinlock_t		asts_spin;<br />
	struct list_head	locks;<br />
	spinlock_t		locks_spin;<br />
	struct list_head	unlocking;<br />
	wait_queue_head_t	wait;<br />
};</p>
<p>static inline int dlm_locking_stopped(struct dlm_ls *ls)<br />
{<br />
	return !test_bit(LSFL_RUNNING, &#038;ls->ls_flags);<br />
}</p>
<p>static inline int dlm_recovery_stopped(struct dlm_ls *ls)<br />
{<br />
	return test_bit(LSFL_RECOVERY_STOP, &#038;ls->ls_flags);<br />
}</p>
<p>static inline int dlm_no_directory(struct dlm_ls *ls)<br />
{<br />
	return (ls->ls_exflags &#038; DLM_LSFL_NODIR) ? 1 : 0;<br />
}</p>
<p>int dlm_netlink_init(void);<br />
void dlm_netlink_exit(void);<br />
void dlm_timeout_warn(struct dlm_lkb *lkb);<br />
int dlm_plock_init(void);<br />
void dlm_plock_exit(void);</p>
<p>#ifdef CONFIG_DLM_DEBUG<br />
int dlm_register_debugfs(void);<br />
void dlm_unregister_debugfs(void);<br />
int dlm_create_debug_file(struct dlm_ls *ls);<br />
void dlm_delete_debug_file(struct dlm_ls *ls);<br />
#else<br />
static inline int dlm_register_debugfs(void) { return 0; }<br />
static inline void dlm_unregister_debugfs(void) { }<br />
static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }<br />
static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }<br />
#endif</p>
<p>#endif				/* __DLM_INTERNAL_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/dlm_internal-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dir.h</title>
		<link>http://lynyrd.ru/dir-h</link>
		<comments>http://lynyrd.ru/dir-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:49:03 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1027</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1027"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __DIR_DOT_H__<br />
#define __DIR_DOT_H__</p>
<p>int dlm_dir_nodeid(struct dlm_rsb *rsb);<br />
int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);<br />
void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);<br />
void dlm_dir_clear(struct dlm_ls *ls);<br />
void dlm_clear_free_entries(struct dlm_ls *ls);<br />
int dlm_recover_directory(struct dlm_ls *ls);<br />
int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,<br />
	int *r_nodeid);<br />
void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,<br />
	char *outbuf, int outlen, int nodeid);</p>
<p>#endif				/* __DIR_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/dir-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dir.c</title>
		<link>http://lynyrd.ru/dir-c-9</link>
		<comments>http://lynyrd.ru/dir-c-9#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:48:46 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1025</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1025"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;rcom.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;memory.h&raquo;<br />
#include &laquo;recover.h&raquo;<br />
#include &laquo;util.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;dir.h&raquo;</p>
<p>static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)<br />
{<br />
	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	list_add(&#038;de->list, &#038;ls->ls_recover_list);<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);<br />
}</p>
<p>static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)<br />
{<br />
	int found = 0;<br />
	struct dlm_direntry *de;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	list_for_each_entry(de, &#038;ls->ls_recover_list, list) {<br />
		if (de->length == len) {<br />
			list_del(&#038;de->list);<br />
			de->master_nodeid = 0;<br />
			memset(de->name, 0, len);<br />
			found = 1;<br />
			break;<br />
		}<br />
	}<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);</p>
<p>	if (!found)<br />
		de = kzalloc(sizeof(struct dlm_direntry) + len,<br />
			     ls->ls_allocation);<br />
	return de;<br />
}</p>
<p>void dlm_clear_free_entries(struct dlm_ls *ls)<br />
{<br />
	struct dlm_direntry *de;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	while (!list_empty(&#038;ls->ls_recover_list)) {<br />
		de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,<br />
				list);<br />
		list_del(&#038;de->list);<br />
		kfree(de);<br />
	}<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);<br />
}</p>
<p>/*<br />
 * We use the upper 16 bits of the hash value to select the directory node.<br />
 * Low bits are used for distribution of rsb&#8217;s among hash buckets on each node.<br />
 *<br />
 * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of<br />
 * num_nodes to the hash value.  This value in the desired range is used as an<br />
 * offset into the sorted list of nodeid&#8217;s to give the particular nodeid.<br />
 */</p>
<p>int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)<br />
{<br />
	struct list_head *tmp;<br />
	struct dlm_member *memb = NULL;<br />
	uint32_t node, n = 0;<br />
	int nodeid;</p>
<p>	if (ls->ls_num_nodes == 1) {<br />
		nodeid = dlm_our_nodeid();<br />
		goto out;<br />
	}</p>
<p>	if (ls->ls_node_array) {<br />
		node = (hash >> 16) % ls->ls_total_weight;<br />
		nodeid = ls->ls_node_array[node];<br />
		goto out;<br />
	}</p>
<p>	/* make_member_array() failed to kmalloc ls_node_array&#8230; */</p>
<p>	node = (hash >> 16) % ls->ls_num_nodes;</p>
<p>	list_for_each(tmp, &#038;ls->ls_nodes) {<br />
		if (n++ != node)<br />
			continue;<br />
		memb = list_entry(tmp, struct dlm_member, list);<br />
		break;<br />
	}</p>
<p>	DLM_ASSERT(memb , printk(&raquo;num_nodes=%u n=%u node=%u\n&raquo;,<br />
				 ls->ls_num_nodes, n, node););<br />
	nodeid = memb->nodeid;<br />
 out:<br />
	return nodeid;<br />
}</p>
<p>int dlm_dir_nodeid(struct dlm_rsb *r)<br />
{<br />
	return dlm_hash2nodeid(r->res_ls, r->res_hash);<br />
}</p>
<p>static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)<br />
{<br />
	uint32_t val;</p>
<p>	val = jhash(name, len, 0);<br />
	val &#038;= (ls->ls_dirtbl_size &#8211; 1);</p>
<p>	return val;<br />
}</p>
<p>static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)<br />
{<br />
	uint32_t bucket;</p>
<p>	bucket = dir_hash(ls, de->name, de->length);<br />
	list_add_tail(&#038;de->list, &#038;ls->ls_dirtbl[bucket].list);<br />
}</p>
<p>static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,<br />
					  int namelen, uint32_t bucket)<br />
{<br />
	struct dlm_direntry *de;</p>
<p>	list_for_each_entry(de, &#038;ls->ls_dirtbl[bucket].list, list) {<br />
		if (de->length == namelen &#038;&#038; !memcmp(name, de->name, namelen))<br />
			goto out;<br />
	}<br />
	de = NULL;<br />
 out:<br />
	return de;<br />
}</p>
<p>void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)<br />
{<br />
	struct dlm_direntry *de;<br />
	uint32_t bucket;</p>
<p>	bucket = dir_hash(ls, name, namelen);</p>
<p>	spin_lock(&#038;ls->ls_dirtbl[bucket].lock);</p>
<p>	de = search_bucket(ls, name, namelen, bucket);</p>
<p>	if (!de) {<br />
		log_error(ls, &laquo;remove fr %u none&raquo;, nodeid);<br />
		goto out;<br />
	}</p>
<p>	if (de->master_nodeid != nodeid) {<br />
		log_error(ls, &laquo;remove fr %u ID %u&raquo;, nodeid, de->master_nodeid);<br />
		goto out;<br />
	}</p>
<p>	list_del(&#038;de->list);<br />
	kfree(de);<br />
 out:<br />
	spin_unlock(&#038;ls->ls_dirtbl[bucket].lock);<br />
}</p>
<p>void dlm_dir_clear(struct dlm_ls *ls)<br />
{<br />
	struct list_head *head;<br />
	struct dlm_direntry *de;<br />
	int i;</p>
<p>	DLM_ASSERT(list_empty(&#038;ls->ls_recover_list), );</p>
<p>	for (i = 0; i < ls->ls_dirtbl_size; i++) {<br />
		spin_lock(&#038;ls->ls_dirtbl[i].lock);<br />
		head = &#038;ls->ls_dirtbl[i].list;<br />
		while (!list_empty(head)) {<br />
			de = list_entry(head->next, struct dlm_direntry, list);<br />
			list_del(&#038;de->list);<br />
			put_free_de(ls, de);<br />
		}<br />
		spin_unlock(&#038;ls->ls_dirtbl[i].lock);<br />
	}<br />
}</p>
<p>int dlm_recover_directory(struct dlm_ls *ls)<br />
{<br />
	struct dlm_member *memb;<br />
	struct dlm_direntry *de;<br />
	char *b, *last_name = NULL;<br />
	int error = -ENOMEM, last_len, count = 0;<br />
	uint16_t namelen;</p>
<p>	log_debug(ls, &laquo;dlm_recover_directory&raquo;);</p>
<p>	if (dlm_no_directory(ls))<br />
		goto out_status;</p>
<p>	dlm_dir_clear(ls);</p>
<p>	last_name = kmalloc(DLM_RESNAME_MAXLEN, ls->ls_allocation);<br />
	if (!last_name)<br />
		goto out;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		memset(last_name, 0, DLM_RESNAME_MAXLEN);<br />
		last_len = 0;</p>
<p>		for (;;) {<br />
			int left;<br />
			error = dlm_recovery_stopped(ls);<br />
			if (error)<br />
				goto out_free;</p>
<p>			error = dlm_rcom_names(ls, memb->nodeid,<br />
					       last_name, last_len);<br />
			if (error)<br />
				goto out_free;</p>
<p>			schedule();</p>
<p>			/*<br />
			 * pick namelen/name pairs out of received buffer<br />
			 */</p>
<p>			b = ls->ls_recover_buf->rc_buf;<br />
			left = ls->ls_recover_buf->rc_header.h_length;<br />
			left -= sizeof(struct dlm_rcom);</p>
<p>			for (;;) {<br />
				__be16 v;</p>
<p>				error = -EINVAL;<br />
				if (left < sizeof(__be16))<br />
					goto out_free;</p>
<p>				memcpy(&#038;v, b, sizeof(__be16));<br />
				namelen = be16_to_cpu(v);<br />
				b += sizeof(__be16);<br />
				left -= sizeof(__be16);</p>
<p>				/* namelen of 0xFFFFF marks end of names for<br />
				   this node; namelen of 0 marks end of the<br />
				   buffer */</p>
<p>				if (namelen == 0xFFFF)<br />
					goto done;<br />
				if (!namelen)<br />
					break;</p>
<p>				if (namelen > left)<br />
					goto out_free;</p>
<p>				if (namelen > DLM_RESNAME_MAXLEN)<br />
					goto out_free;</p>
<p>				error = -ENOMEM;<br />
				de = get_free_de(ls, namelen);<br />
				if (!de)<br />
					goto out_free;</p>
<p>				de->master_nodeid = memb->nodeid;<br />
				de->length = namelen;<br />
				last_len = namelen;<br />
				memcpy(de->name, b, namelen);<br />
				memcpy(last_name, b, namelen);<br />
				b += namelen;<br />
				left -= namelen;</p>
<p>				add_entry_to_hash(ls, de);<br />
				count++;<br />
			}<br />
		}<br />
         done:<br />
		;<br />
	}</p>
<p> out_status:<br />
	error = 0;<br />
	dlm_set_recover_status(ls, DLM_RS_DIR);<br />
	log_debug(ls, &laquo;dlm_recover_directory %d entries&raquo;, count);<br />
 out_free:<br />
	kfree(last_name);<br />
 out:<br />
	dlm_clear_free_entries(ls);<br />
	return error;<br />
}</p>
<p>static int get_entry(struct dlm_ls *ls, int nodeid, char *name,<br />
		     int namelen, int *r_nodeid)<br />
{<br />
	struct dlm_direntry *de, *tmp;<br />
	uint32_t bucket;</p>
<p>	bucket = dir_hash(ls, name, namelen);</p>
<p>	spin_lock(&#038;ls->ls_dirtbl[bucket].lock);<br />
	de = search_bucket(ls, name, namelen, bucket);<br />
	if (de) {<br />
		*r_nodeid = de->master_nodeid;<br />
		spin_unlock(&#038;ls->ls_dirtbl[bucket].lock);<br />
		if (*r_nodeid == nodeid)<br />
			return -EEXIST;<br />
		return 0;<br />
	}</p>
<p>	spin_unlock(&#038;ls->ls_dirtbl[bucket].lock);</p>
<p>	if (namelen > DLM_RESNAME_MAXLEN)<br />
		return -EINVAL;</p>
<p>	de = kzalloc(sizeof(struct dlm_direntry) + namelen, ls->ls_allocation);<br />
	if (!de)<br />
		return -ENOMEM;</p>
<p>	de->master_nodeid = nodeid;<br />
	de->length = namelen;<br />
	memcpy(de->name, name, namelen);</p>
<p>	spin_lock(&#038;ls->ls_dirtbl[bucket].lock);<br />
	tmp = search_bucket(ls, name, namelen, bucket);<br />
	if (tmp) {<br />
		kfree(de);<br />
		de = tmp;<br />
	} else {<br />
		list_add_tail(&#038;de->list, &#038;ls->ls_dirtbl[bucket].list);<br />
	}<br />
	*r_nodeid = de->master_nodeid;<br />
	spin_unlock(&#038;ls->ls_dirtbl[bucket].lock);<br />
	return 0;<br />
}</p>
<p>int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,<br />
		   int *r_nodeid)<br />
{<br />
	return get_entry(ls, nodeid, name, namelen, r_nodeid);<br />
}</p>
<p>static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)<br />
{<br />
	struct dlm_rsb *r;</p>
<p>	down_read(&#038;ls->ls_root_sem);<br />
	list_for_each_entry(r, &#038;ls->ls_root_list, res_root_list) {<br />
		if (len == r->res_length &#038;&#038; !memcmp(name, r->res_name, len)) {<br />
			up_read(&#038;ls->ls_root_sem);<br />
			return r;<br />
		}<br />
	}<br />
	up_read(&#038;ls->ls_root_sem);<br />
	return NULL;<br />
}</p>
<p>/* Find the rsb where we left off (or start again), then send rsb names<br />
   for rsb&#8217;s we&#8217;re master of and whose directory node matches the requesting<br />
   node.  inbuf is the rsb name last sent, inlen is the name&#8217;s length */</p>
<p>void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,<br />
 			   char *outbuf, int outlen, int nodeid)<br />
{<br />
	struct list_head *list;<br />
	struct dlm_rsb *r;<br />
	int offset = 0, dir_nodeid;<br />
	__be16 be_namelen;</p>
<p>	down_read(&#038;ls->ls_root_sem);</p>
<p>	if (inlen > 1) {<br />
		r = find_rsb_root(ls, inbuf, inlen);<br />
		if (!r) {<br />
			inbuf[inlen - 1] = &#8216;\0&#8242;;<br />
			log_error(ls, &laquo;copy_master_names from %d start %d %s&raquo;,<br />
				  nodeid, inlen, inbuf);<br />
			goto out;<br />
		}<br />
		list = r->res_root_list.next;<br />
	} else {<br />
		list = ls->ls_root_list.next;<br />
	}</p>
<p>	for (offset = 0; list != &#038;ls->ls_root_list; list = list->next) {<br />
		r = list_entry(list, struct dlm_rsb, res_root_list);<br />
		if (r->res_nodeid)<br />
			continue;</p>
<p>		dir_nodeid = dlm_dir_nodeid(r);<br />
		if (dir_nodeid != nodeid)<br />
			continue;</p>
<p>		/*<br />
		 * The block ends when we can&#8217;t fit the following in the<br />
		 * remaining buffer space:<br />
		 * namelen (uint16_t) +<br />
		 * name (r->res_length) +<br />
		 * end-of-block record 0&#215;0000 (uint16_t)<br />
		 */</p>
<p>		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {<br />
			/* Write end-of-block record */<br />
			be_namelen = cpu_to_be16(0);<br />
			memcpy(outbuf + offset, &#038;be_namelen, sizeof(__be16));<br />
			offset += sizeof(__be16);<br />
			goto out;<br />
		}</p>
<p>		be_namelen = cpu_to_be16(r->res_length);<br />
		memcpy(outbuf + offset, &#038;be_namelen, sizeof(__be16));<br />
		offset += sizeof(__be16);<br />
		memcpy(outbuf + offset, r->res_name, r->res_length);<br />
		offset += r->res_length;<br />
	}</p>
<p>	/*<br />
	 * If we&#8217;ve reached the end of the list (and there&#8217;s room) write a<br />
	 * terminating record.<br />
	 */</p>
<p>	if ((list == &#038;ls->ls_root_list) &#038;&#038;<br />
	    (offset + sizeof(uint16_t) <= outlen)) {<br />
		be_namelen = cpu_to_be16(0xFFFF);<br />
		memcpy(outbuf + offset, &#038;be_namelen, sizeof(__be16));<br />
		offset += sizeof(__be16);<br />
	}</p>
<p> out:<br />
	up_read(&#038;ls->ls_root_sem);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/dir-c-9/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>debug_fs.c</title>
		<link>http://lynyrd.ru/debug_fs-c</link>
		<comments>http://lynyrd.ru/debug_fs-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:48:28 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1023</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2009 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 &#171;dlm_internal.h&#187;
#include &#171;lock.h&#187;
#define DLM_DEBUG_BUF_LEN 4096
static char debug_buf[DLM_DEBUG_BUF_LEN];
static struct mutex debug_buf_lock;
static struct dentry ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.<span id="more-1023"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include
<linux/pagemap.h>
#include
<linux/seq_file.h>
#include
<linux/module.h>
#include
<linux/ctype.h>
#include
<linux/debugfs.h>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lock.h&raquo;</p>
<p>#define DLM_DEBUG_BUF_LEN 4096<br />
static char debug_buf[DLM_DEBUG_BUF_LEN];<br />
static struct mutex debug_buf_lock;</p>
<p>static struct dentry *dlm_root;</p>
<p>static char *print_lockmode(int mode)<br />
{<br />
	switch (mode) {<br />
	case DLM_LOCK_IV:<br />
		return &laquo;&#8211;&raquo;;<br />
	case DLM_LOCK_NL:<br />
		return &laquo;NL&raquo;;<br />
	case DLM_LOCK_CR:<br />
		return &laquo;CR&raquo;;<br />
	case DLM_LOCK_CW:<br />
		return &laquo;CW&raquo;;<br />
	case DLM_LOCK_PR:<br />
		return &laquo;PR&raquo;;<br />
	case DLM_LOCK_PW:<br />
		return &laquo;PW&raquo;;<br />
	case DLM_LOCK_EX:<br />
		return &laquo;EX&raquo;;<br />
	default:<br />
		return &laquo;??&raquo;;<br />
	}<br />
}</p>
<p>static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,<br />
			      struct dlm_rsb *res)<br />
{<br />
	seq_printf(s, &laquo;%08x %s&raquo;, lkb->lkb_id, print_lockmode(lkb->lkb_grmode));</p>
<p>	if (lkb->lkb_status == DLM_LKSTS_CONVERT ||<br />
	    lkb->lkb_status == DLM_LKSTS_WAITING)<br />
		seq_printf(s, &raquo; (%s)&raquo;, print_lockmode(lkb->lkb_rqmode));</p>
<p>	if (lkb->lkb_nodeid) {<br />
		if (lkb->lkb_nodeid != res->res_nodeid)<br />
			seq_printf(s, &raquo; Remote: %3d %08x&raquo;, lkb->lkb_nodeid,<br />
				   lkb->lkb_remid);<br />
		else<br />
			seq_printf(s, &raquo; Master:     %08x&raquo;, lkb->lkb_remid);<br />
	}</p>
<p>	if (lkb->lkb_wait_type)<br />
		seq_printf(s, &raquo; wait_type: %d&raquo;, lkb->lkb_wait_type);</p>
<p>	return seq_printf(s, &laquo;\n&raquo;);<br />
}</p>
<p>static int print_format1(struct dlm_rsb *res, struct seq_file *s)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;<br />
	int rv;</p>
<p>	lock_rsb(res);</p>
<p>	rv = seq_printf(s, &laquo;\nResource %p Name (len=%d) \&raquo;",<br />
			res, res->res_length);<br />
	if (rv)<br />
		goto out;</p>
<p>	for (i = 0; i < res->res_length; i++) {<br />
		if (isprint(res->res_name[i]))<br />
			seq_printf(s, &laquo;%c&raquo;, res->res_name[i]);<br />
		else<br />
			seq_printf(s, &laquo;%c&raquo;, &#8216;.&#8217;);<br />
	}</p>
<p>	if (res->res_nodeid > 0)<br />
		rv = seq_printf(s, &laquo;\&raquo;  \nLocal Copy, Master is node %d\n&raquo;,<br />
				res->res_nodeid);<br />
	else if (res->res_nodeid == 0)<br />
		rv = seq_printf(s, &laquo;\&raquo;  \nMaster Copy\n&raquo;);<br />
	else if (res->res_nodeid == -1)<br />
		rv = seq_printf(s, &laquo;\&raquo;  \nLooking up master (lkid %x)\n&raquo;,<br />
			   	res->res_first_lkid);<br />
	else<br />
		rv = seq_printf(s, &laquo;\&raquo;  \nInvalid master %d\n&raquo;,<br />
				res->res_nodeid);<br />
	if (rv)<br />
		goto out;</p>
<p>	/* Print the LVB: */<br />
	if (res->res_lvbptr) {<br />
		seq_printf(s, &laquo;LVB: &laquo;);<br />
		for (i = 0; i < lvblen; i++) {<br />
			if (i == lvblen / 2)<br />
				seq_printf(s, "\n     ");<br />
			seq_printf(s, "%02x ",<br />
				   (unsigned char) res->res_lvbptr[i]);<br />
		}<br />
		if (rsb_flag(res, RSB_VALNOTVALID))<br />
			seq_printf(s, &raquo; (INVALID)&raquo;);<br />
		rv = seq_printf(s, &laquo;\n&raquo;);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	root_list = !list_empty(&#038;res->res_root_list);<br />
	recover_list = !list_empty(&#038;res->res_recover_list);</p>
<p>	if (root_list || recover_list) {<br />
		rv = seq_printf(s, &laquo;Recovery: root %d recover %d flags %lx &raquo;<br />
				&laquo;count %d\n&raquo;, root_list, recover_list,<br />
			   	res->res_flags, res->res_recover_locks_count);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	/* Print the locks attached to this resource */<br />
	seq_printf(s, &laquo;Granted Queue\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;res->res_grantqueue, lkb_statequeue) {<br />
		rv = print_format1_lock(s, lkb, res);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	seq_printf(s, &laquo;Conversion Queue\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;res->res_convertqueue, lkb_statequeue) {<br />
		rv = print_format1_lock(s, lkb, res);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	seq_printf(s, &laquo;Waiting Queue\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;res->res_waitqueue, lkb_statequeue) {<br />
		rv = print_format1_lock(s, lkb, res);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	if (list_empty(&#038;res->res_lookup))<br />
		goto out;</p>
<p>	seq_printf(s, &laquo;Lookup Queue\n&raquo;);<br />
	list_for_each_entry(lkb, &#038;res->res_lookup, lkb_rsb_lookup) {<br />
		rv = seq_printf(s, &laquo;%08x %s&raquo;, lkb->lkb_id,<br />
				print_lockmode(lkb->lkb_rqmode));<br />
		if (lkb->lkb_wait_type)<br />
			seq_printf(s, &raquo; wait_type: %d&raquo;, lkb->lkb_wait_type);<br />
		rv = seq_printf(s, &laquo;\n&raquo;);<br />
	}<br />
 out:<br />
	unlock_rsb(res);<br />
	return rv;<br />
}</p>
<p>static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,<br />
			      struct dlm_rsb *r)<br />
{<br />
	u64 xid = 0;<br />
	u64 us;<br />
	int rv;</p>
<p>	if (lkb->lkb_flags &#038; DLM_IFL_USER) {<br />
		if (lkb->lkb_ua)<br />
			xid = lkb->lkb_ua->xid;<br />
	}</p>
<p>	/* microseconds since lkb was added to current queue */<br />
	us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp));</p>
<p>	/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us<br />
	   r_nodeid r_len r_name */</p>
<p>	rv = seq_printf(s, &laquo;%x %d %x %u %llu %x %x %d %d %d %llu %u %d \&raquo;%s\&raquo;\n&raquo;,<br />
			lkb->lkb_id,<br />
			lkb->lkb_nodeid,<br />
			lkb->lkb_remid,<br />
			lkb->lkb_ownpid,<br />
			(unsigned long long)xid,<br />
			lkb->lkb_exflags,<br />
			lkb->lkb_flags,<br />
			lkb->lkb_status,<br />
			lkb->lkb_grmode,<br />
			lkb->lkb_rqmode,<br />
			(unsigned long long)us,<br />
			r->res_nodeid,<br />
			r->res_length,<br />
			r->res_name);<br />
	return rv;<br />
}</p>
<p>static int print_format2(struct dlm_rsb *r, struct seq_file *s)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int rv = 0;</p>
<p>	lock_rsb(r);</p>
<p>	list_for_each_entry(lkb, &#038;r->res_grantqueue, lkb_statequeue) {<br />
		rv = print_format2_lock(s, lkb, r);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		rv = print_format2_lock(s, lkb, r);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_waitqueue, lkb_statequeue) {<br />
		rv = print_format2_lock(s, lkb, r);<br />
		if (rv)<br />
			goto out;<br />
	}<br />
 out:<br />
	unlock_rsb(r);<br />
	return rv;<br />
}</p>
<p>static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,<br />
			      int rsb_lookup)<br />
{<br />
	u64 xid = 0;<br />
	int rv;</p>
<p>	if (lkb->lkb_flags &#038; DLM_IFL_USER) {<br />
		if (lkb->lkb_ua)<br />
			xid = lkb->lkb_ua->xid;<br />
	}</p>
<p>	rv = seq_printf(s, &laquo;lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n&raquo;,<br />
			lkb->lkb_id,<br />
			lkb->lkb_nodeid,<br />
			lkb->lkb_remid,<br />
			lkb->lkb_ownpid,<br />
			(unsigned long long)xid,<br />
			lkb->lkb_exflags,<br />
			lkb->lkb_flags,<br />
			lkb->lkb_status,<br />
			lkb->lkb_grmode,<br />
			lkb->lkb_rqmode,<br />
			lkb->lkb_highbast,<br />
			rsb_lookup,<br />
			lkb->lkb_wait_type,<br />
			lkb->lkb_lvbseq,<br />
			(unsigned long long)ktime_to_ns(lkb->lkb_timestamp),<br />
			(unsigned long long)ktime_to_ns(lkb->lkb_time_bast));<br />
	return rv;<br />
}</p>
<p>static int print_format3(struct dlm_rsb *r, struct seq_file *s)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int i, lvblen = r->res_ls->ls_lvblen;<br />
	int print_name = 1;<br />
	int rv;</p>
<p>	lock_rsb(r);</p>
<p>	rv = seq_printf(s, &laquo;rsb %p %d %x %lx %d %d %u %d &laquo;,<br />
			r,<br />
			r->res_nodeid,<br />
			r->res_first_lkid,<br />
			r->res_flags,<br />
			!list_empty(&#038;r->res_root_list),<br />
			!list_empty(&#038;r->res_recover_list),<br />
			r->res_recover_locks_count,<br />
			r->res_length);<br />
	if (rv)<br />
		goto out;</p>
<p>	for (i = 0; i < r->res_length; i++) {<br />
		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))<br />
			print_name = 0;<br />
	}</p>
<p>	seq_printf(s, &laquo;%s&raquo;, print_name ? &laquo;str &raquo; : &laquo;hex&raquo;);</p>
<p>	for (i = 0; i < r->res_length; i++) {<br />
		if (print_name)<br />
			seq_printf(s, &laquo;%c&raquo;, r->res_name[i]);<br />
		else<br />
			seq_printf(s, &raquo; %02x&raquo;, (unsigned char)r->res_name[i]);<br />
	}<br />
	rv = seq_printf(s, &laquo;\n&raquo;);<br />
	if (rv)<br />
		goto out;</p>
<p>	if (!r->res_lvbptr)<br />
		goto do_locks;</p>
<p>	seq_printf(s, &laquo;lvb %u %d&raquo;, r->res_lvbseq, lvblen);</p>
<p>	for (i = 0; i < lvblen; i++)<br />
		seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);<br />
	rv = seq_printf(s, &laquo;\n&raquo;);<br />
	if (rv)<br />
		goto out;</p>
<p> do_locks:<br />
	list_for_each_entry(lkb, &#038;r->res_grantqueue, lkb_statequeue) {<br />
		rv = print_format3_lock(s, lkb, 0);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		rv = print_format3_lock(s, lkb, 0);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_waitqueue, lkb_statequeue) {<br />
		rv = print_format3_lock(s, lkb, 0);<br />
		if (rv)<br />
			goto out;<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_lookup, lkb_rsb_lookup) {<br />
		rv = print_format3_lock(s, lkb, 1);<br />
		if (rv)<br />
			goto out;<br />
	}<br />
 out:<br />
	unlock_rsb(r);<br />
	return rv;<br />
}</p>
<p>struct rsbtbl_iter {<br />
	struct dlm_rsb *rsb;<br />
	unsigned bucket;<br />
	int format;<br />
	int header;<br />
};</p>
<p>/* seq_printf returns -1 if the buffer is full, and 0 otherwise.<br />
   If the buffer is full, seq_printf can be called again, but it<br />
   does nothing and just returns -1.  So, the these printing routines<br />
   periodically check the return value to avoid wasting too much time<br />
   trying to print to a full buffer. */</p>
<p>static int table_seq_show(struct seq_file *seq, void *iter_ptr)<br />
{<br />
	struct rsbtbl_iter *ri = iter_ptr;<br />
	int rv = 0;</p>
<p>	switch (ri->format) {<br />
	case 1:<br />
		rv = print_format1(ri->rsb, seq);<br />
		break;<br />
	case 2:<br />
		if (ri->header) {<br />
			seq_printf(seq, &laquo;id nodeid remid pid xid exflags &raquo;<br />
					&laquo;flags sts grmode rqmode time_ms &raquo;<br />
					&laquo;r_nodeid r_len r_name\n&raquo;);<br />
			ri->header = 0;<br />
		}<br />
		rv = print_format2(ri->rsb, seq);<br />
		break;<br />
	case 3:<br />
		if (ri->header) {<br />
			seq_printf(seq, &laquo;version rsb 1.1 lvb 1.1 lkb 1.1\n&raquo;);<br />
			ri->header = 0;<br />
		}<br />
		rv = print_format3(ri->rsb, seq);<br />
		break;<br />
	}</p>
<p>	return rv;<br />
}</p>
<p>static const struct seq_operations format1_seq_ops;<br />
static const struct seq_operations format2_seq_ops;<br />
static const struct seq_operations format3_seq_ops;</p>
<p>static void *table_seq_start(struct seq_file *seq, loff_t *pos)<br />
{<br />
	struct dlm_ls *ls = seq->private;<br />
	struct rsbtbl_iter *ri;<br />
	struct dlm_rsb *r;<br />
	loff_t n = *pos;<br />
	unsigned bucket, entry;</p>
<p>	bucket = n >> 32;<br />
	entry = n &#038; ((1LL << 32) - 1);</p>
<p>	if (bucket >= ls->ls_rsbtbl_size)<br />
		return NULL;</p>
<p>	ri = kzalloc(sizeof(struct rsbtbl_iter), GFP_KERNEL);<br />
	if (!ri)<br />
		return NULL;<br />
	if (n == 0)<br />
		ri->header = 1;<br />
	if (seq->op == &#038;format1_seq_ops)<br />
		ri->format = 1;<br />
	if (seq->op == &#038;format2_seq_ops)<br />
		ri->format = 2;<br />
	if (seq->op == &#038;format3_seq_ops)<br />
		ri->format = 3;</p>
<p>	spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	if (!list_empty(&#038;ls->ls_rsbtbl[bucket].list)) {<br />
		list_for_each_entry(r, &#038;ls->ls_rsbtbl[bucket].list,<br />
				    res_hashchain) {<br />
			if (!entry&#8211;) {<br />
				dlm_hold_rsb(r);<br />
				ri->rsb = r;<br />
				ri->bucket = bucket;<br />
				spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
				return ri;<br />
			}<br />
		}<br />
	}<br />
	spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);</p>
<p>	/*<br />
	 * move to the first rsb in the next non-empty bucket<br />
	 */</p>
<p>	/* zero the entry */<br />
	n &#038;= ~((1LL << 32) - 1);</p>
<p>	while (1) {<br />
		bucket++;<br />
		n += 1LL << 32;</p>
<p>		if (bucket >= ls->ls_rsbtbl_size) {<br />
			kfree(ri);<br />
			return NULL;<br />
		}</p>
<p>		spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
		if (!list_empty(&#038;ls->ls_rsbtbl[bucket].list)) {<br />
			r = list_first_entry(&#038;ls->ls_rsbtbl[bucket].list,<br />
					     struct dlm_rsb, res_hashchain);<br />
			dlm_hold_rsb(r);<br />
			ri->rsb = r;<br />
			ri->bucket = bucket;<br />
			spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
			*pos = n;<br />
			return ri;<br />
		}<br />
		spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	}<br />
}</p>
<p>static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)<br />
{<br />
	struct dlm_ls *ls = seq->private;<br />
	struct rsbtbl_iter *ri = iter_ptr;<br />
	struct list_head *next;<br />
	struct dlm_rsb *r, *rp;<br />
	loff_t n = *pos;<br />
	unsigned bucket;</p>
<p>	bucket = n >> 32;</p>
<p>	/*<br />
	 * move to the next rsb in the same bucket<br />
	 */</p>
<p>	spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	rp = ri->rsb;<br />
	next = rp->res_hashchain.next;</p>
<p>	if (next != &#038;ls->ls_rsbtbl[bucket].list) {<br />
		r = list_entry(next, struct dlm_rsb, res_hashchain);<br />
		dlm_hold_rsb(r);<br />
		ri->rsb = r;<br />
		spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
		dlm_put_rsb(rp);<br />
		++*pos;<br />
		return ri;<br />
	}<br />
	spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	dlm_put_rsb(rp);</p>
<p>	/*<br />
	 * move to the first rsb in the next non-empty bucket<br />
	 */</p>
<p>	/* zero the entry */<br />
	n &#038;= ~((1LL << 32) - 1);</p>
<p>	while (1) {<br />
		bucket++;<br />
		n += 1LL << 32;</p>
<p>		if (bucket >= ls->ls_rsbtbl_size) {<br />
			kfree(ri);<br />
			return NULL;<br />
		}</p>
<p>		spin_lock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
		if (!list_empty(&#038;ls->ls_rsbtbl[bucket].list)) {<br />
			r = list_first_entry(&#038;ls->ls_rsbtbl[bucket].list,<br />
					     struct dlm_rsb, res_hashchain);<br />
			dlm_hold_rsb(r);<br />
			ri->rsb = r;<br />
			ri->bucket = bucket;<br />
			spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
			*pos = n;<br />
			return ri;<br />
		}<br />
		spin_unlock(&#038;ls->ls_rsbtbl[bucket].lock);<br />
	}<br />
}</p>
<p>static void table_seq_stop(struct seq_file *seq, void *iter_ptr)<br />
{<br />
	struct rsbtbl_iter *ri = iter_ptr;</p>
<p>	if (ri) {<br />
		dlm_put_rsb(ri->rsb);<br />
		kfree(ri);<br />
	}<br />
}</p>
<p>static const struct seq_operations format1_seq_ops = {<br />
	.start = table_seq_start,<br />
	.next  = table_seq_next,<br />
	.stop  = table_seq_stop,<br />
	.show  = table_seq_show,<br />
};</p>
<p>static const struct seq_operations format2_seq_ops = {<br />
	.start = table_seq_start,<br />
	.next  = table_seq_next,<br />
	.stop  = table_seq_stop,<br />
	.show  = table_seq_show,<br />
};</p>
<p>static const struct seq_operations format3_seq_ops = {<br />
	.start = table_seq_start,<br />
	.next  = table_seq_next,<br />
	.stop  = table_seq_stop,<br />
	.show  = table_seq_show,<br />
};</p>
<p>static const struct file_operations format1_fops;<br />
static const struct file_operations format2_fops;<br />
static const struct file_operations format3_fops;</p>
<p>static int table_open(struct inode *inode, struct file *file)<br />
{<br />
	struct seq_file *seq;<br />
	int ret = -1;</p>
<p>	if (file->f_op == &#038;format1_fops)<br />
		ret = seq_open(file, &#038;format1_seq_ops);<br />
	else if (file->f_op == &#038;format2_fops)<br />
		ret = seq_open(file, &#038;format2_seq_ops);<br />
	else if (file->f_op == &#038;format3_fops)<br />
		ret = seq_open(file, &#038;format3_seq_ops);</p>
<p>	if (ret)<br />
		return ret;</p>
<p>	seq = file->private_data;<br />
	seq->private = inode->i_private; /* the dlm_ls */<br />
	return 0;<br />
}</p>
<p>static const struct file_operations format1_fops = {<br />
	.owner   = THIS_MODULE,<br />
	.open    = table_open,<br />
	.read    = seq_read,<br />
	.llseek  = seq_lseek,<br />
	.release = seq_release<br />
};</p>
<p>static const struct file_operations format2_fops = {<br />
	.owner   = THIS_MODULE,<br />
	.open    = table_open,<br />
	.read    = seq_read,<br />
	.llseek  = seq_lseek,<br />
	.release = seq_release<br />
};</p>
<p>static const struct file_operations format3_fops = {<br />
	.owner   = THIS_MODULE,<br />
	.open    = table_open,<br />
	.read    = seq_read,<br />
	.llseek  = seq_lseek,<br />
	.release = seq_release<br />
};</p>
<p>/*<br />
 * dump lkb&#8217;s on the ls_waiters list<br />
 */</p>
<p>static int waiters_open(struct inode *inode, struct file *file)<br />
{<br />
	file->private_data = inode->i_private;<br />
	return 0;<br />
}</p>
<p>static ssize_t waiters_read(struct file *file, char __user *userbuf,<br />
			    size_t count, loff_t *ppos)<br />
{<br />
	struct dlm_ls *ls = file->private_data;<br />
	struct dlm_lkb *lkb;<br />
	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;</p>
<p>	mutex_lock(&#038;debug_buf_lock);<br />
	mutex_lock(&#038;ls->ls_waiters_mutex);<br />
	memset(debug_buf, 0, sizeof(debug_buf));</p>
<p>	list_for_each_entry(lkb, &#038;ls->ls_waiters, lkb_wait_reply) {<br />
		ret = snprintf(debug_buf + pos, len &#8211; pos, &laquo;%x %d %d %s\n&raquo;,<br />
			       lkb->lkb_id, lkb->lkb_wait_type,<br />
			       lkb->lkb_nodeid, lkb->lkb_resource->res_name);<br />
		if (ret >= len &#8211; pos)<br />
			break;<br />
		pos += ret;<br />
	}<br />
	mutex_unlock(&#038;ls->ls_waiters_mutex);</p>
<p>	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);<br />
	mutex_unlock(&#038;debug_buf_lock);<br />
	return rv;<br />
}</p>
<p>static const struct file_operations waiters_fops = {<br />
	.owner   = THIS_MODULE,<br />
	.open    = waiters_open,<br />
	.read    = waiters_read<br />
};</p>
<p>void dlm_delete_debug_file(struct dlm_ls *ls)<br />
{<br />
	if (ls->ls_debug_rsb_dentry)<br />
		debugfs_remove(ls->ls_debug_rsb_dentry);<br />
	if (ls->ls_debug_waiters_dentry)<br />
		debugfs_remove(ls->ls_debug_waiters_dentry);<br />
	if (ls->ls_debug_locks_dentry)<br />
		debugfs_remove(ls->ls_debug_locks_dentry);<br />
	if (ls->ls_debug_all_dentry)<br />
		debugfs_remove(ls->ls_debug_all_dentry);<br />
}</p>
<p>int dlm_create_debug_file(struct dlm_ls *ls)<br />
{<br />
	char name[DLM_LOCKSPACE_LEN+8];</p>
<p>	/* format 1 */</p>
<p>	ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,<br />
						      S_IFREG | S_IRUGO,<br />
						      dlm_root,<br />
						      ls,<br />
						      &#038;format1_fops);<br />
	if (!ls->ls_debug_rsb_dentry)<br />
		goto fail;</p>
<p>	/* format 2 */</p>
<p>	memset(name, 0, sizeof(name));<br />
	snprintf(name, DLM_LOCKSPACE_LEN+8, &laquo;%s_locks&raquo;, ls->ls_name);</p>
<p>	ls->ls_debug_locks_dentry = debugfs_create_file(name,<br />
							S_IFREG | S_IRUGO,<br />
							dlm_root,<br />
							ls,<br />
							&#038;format2_fops);<br />
	if (!ls->ls_debug_locks_dentry)<br />
		goto fail;</p>
<p>	/* format 3 */</p>
<p>	memset(name, 0, sizeof(name));<br />
	snprintf(name, DLM_LOCKSPACE_LEN+8, &laquo;%s_all&raquo;, ls->ls_name);</p>
<p>	ls->ls_debug_all_dentry = debugfs_create_file(name,<br />
						      S_IFREG | S_IRUGO,<br />
						      dlm_root,<br />
						      ls,<br />
						      &#038;format3_fops);<br />
	if (!ls->ls_debug_all_dentry)<br />
		goto fail;</p>
<p>	memset(name, 0, sizeof(name));<br />
	snprintf(name, DLM_LOCKSPACE_LEN+8, &laquo;%s_waiters&raquo;, ls->ls_name);</p>
<p>	ls->ls_debug_waiters_dentry = debugfs_create_file(name,<br />
							  S_IFREG | S_IRUGO,<br />
							  dlm_root,<br />
							  ls,<br />
							  &#038;waiters_fops);<br />
	if (!ls->ls_debug_waiters_dentry)<br />
		goto fail;</p>
<p>	return 0;</p>
<p> fail:<br />
	dlm_delete_debug_file(ls);<br />
	return -ENOMEM;<br />
}</p>
<p>int __init dlm_register_debugfs(void)<br />
{<br />
	mutex_init(&#038;debug_buf_lock);<br />
	dlm_root = debugfs_create_dir(&raquo;dlm&raquo;, NULL);<br />
	return dlm_root ? 0 : -ENOMEM;<br />
}</p>
<p>void dlm_unregister_debugfs(void)<br />
{<br />
	debugfs_remove(dlm_root);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/debug_fs-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>config.h</title>
		<link>http://lynyrd.ru/config-h</link>
		<comments>http://lynyrd.ru/config-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:47:54 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1021</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2007 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1021"></span><br />
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __CONFIG_DOT_H__<br />
#define __CONFIG_DOT_H__</p>
<p>#define DLM_MAX_ADDR_COUNT 3</p>
<p>struct dlm_config_info {<br />
	int ci_tcp_port;<br />
	int ci_buffer_size;<br />
	int ci_rsbtbl_size;<br />
	int ci_lkbtbl_size;<br />
	int ci_dirtbl_size;<br />
	int ci_recover_timer;<br />
	int ci_toss_secs;<br />
	int ci_scan_secs;<br />
	int ci_log_debug;<br />
	int ci_protocol;<br />
	int ci_timewarn_cs;<br />
};</p>
<p>extern struct dlm_config_info dlm_config;</p>
<p>int dlm_config_init(void);<br />
void dlm_config_exit(void);<br />
int dlm_node_weight(char *lsname, int nodeid);<br />
int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,<br />
		    int **new_out, int *new_count_out);<br />
int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);<br />
int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);<br />
int dlm_our_nodeid(void);<br />
int dlm_our_addr(struct sockaddr_storage *addr, int num);</p>
<p>#endif				/* __CONFIG_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/config-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>config.c</title>
		<link>http://lynyrd.ru/config-c-2</link>
		<comments>http://lynyrd.ru/config-c-2#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:47:36 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/config-c-2</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2008 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1020"></span><br />
**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include
<linux/kernel.h>
#include
<linux/module.h>
#include
<linux/configfs.h>
#include
<linux/in.h>
#include
<linux/in6.h>
#include <net/ipv6.h><br />
#include <net/sock.h></p>
<p>#include &laquo;config.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;</p>
<p>/*<br />
 * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid<br />
 * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight<br />
 * /config/dlm/<cluster>/comms/<comm>/nodeid<br />
 * /config/dlm/<cluster>/comms/<comm>/local<br />
 * /config/dlm/<cluster>/comms/<comm>/addr<br />
 * The <cluster> level is useless, but I haven&#8217;t figured out how to avoid it.<br />
 */</p>
<p>static struct config_group *space_list;<br />
static struct config_group *comm_list;<br />
static struct dlm_comm *local_comm;</p>
<p>struct dlm_clusters;<br />
struct dlm_cluster;<br />
struct dlm_spaces;<br />
struct dlm_space;<br />
struct dlm_comms;<br />
struct dlm_comm;<br />
struct dlm_nodes;<br />
struct dlm_node;</p>
<p>static struct config_group *make_cluster(struct config_group *, const char *);<br />
static void drop_cluster(struct config_group *, struct config_item *);<br />
static void release_cluster(struct config_item *);<br />
static struct config_group *make_space(struct config_group *, const char *);<br />
static void drop_space(struct config_group *, struct config_item *);<br />
static void release_space(struct config_item *);<br />
static struct config_item *make_comm(struct config_group *, const char *);<br />
static void drop_comm(struct config_group *, struct config_item *);<br />
static void release_comm(struct config_item *);<br />
static struct config_item *make_node(struct config_group *, const char *);<br />
static void drop_node(struct config_group *, struct config_item *);<br />
static void release_node(struct config_item *);</p>
<p>static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,<br />
			    char *buf);<br />
static ssize_t store_cluster(struct config_item *i,<br />
			     struct configfs_attribute *a,<br />
			     const char *buf, size_t len);<br />
static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,<br />
			 char *buf);<br />
static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,<br />
			  const char *buf, size_t len);<br />
static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,<br />
			 char *buf);<br />
static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,<br />
			  const char *buf, size_t len);</p>
<p>static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf);<br />
static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf,<br />
				size_t len);<br />
static ssize_t comm_local_read(struct dlm_comm *cm, char *buf);<br />
static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,<br />
				size_t len);<br />
static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf,<br />
				size_t len);<br />
static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf);<br />
static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,<br />
				size_t len);<br />
static ssize_t node_weight_read(struct dlm_node *nd, char *buf);<br />
static ssize_t node_weight_write(struct dlm_node *nd, const char *buf,<br />
				size_t len);</p>
<p>struct dlm_cluster {<br />
	struct config_group group;<br />
	unsigned int cl_tcp_port;<br />
	unsigned int cl_buffer_size;<br />
	unsigned int cl_rsbtbl_size;<br />
	unsigned int cl_lkbtbl_size;<br />
	unsigned int cl_dirtbl_size;<br />
	unsigned int cl_recover_timer;<br />
	unsigned int cl_toss_secs;<br />
	unsigned int cl_scan_secs;<br />
	unsigned int cl_log_debug;<br />
	unsigned int cl_protocol;<br />
	unsigned int cl_timewarn_cs;<br />
};</p>
<p>enum {<br />
	CLUSTER_ATTR_TCP_PORT = 0,<br />
	CLUSTER_ATTR_BUFFER_SIZE,<br />
	CLUSTER_ATTR_RSBTBL_SIZE,<br />
	CLUSTER_ATTR_LKBTBL_SIZE,<br />
	CLUSTER_ATTR_DIRTBL_SIZE,<br />
	CLUSTER_ATTR_RECOVER_TIMER,<br />
	CLUSTER_ATTR_TOSS_SECS,<br />
	CLUSTER_ATTR_SCAN_SECS,<br />
	CLUSTER_ATTR_LOG_DEBUG,<br />
	CLUSTER_ATTR_PROTOCOL,<br />
	CLUSTER_ATTR_TIMEWARN_CS,<br />
};</p>
<p>struct cluster_attribute {<br />
	struct configfs_attribute attr;<br />
	ssize_t (*show)(struct dlm_cluster *, char *);<br />
	ssize_t (*store)(struct dlm_cluster *, const char *, size_t);<br />
};</p>
<p>static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,<br />
			   int *info_field, int check_zero,<br />
			   const char *buf, size_t len)<br />
{<br />
	unsigned int x;</p>
<p>	if (!capable(CAP_SYS_ADMIN))<br />
		return -EACCES;</p>
<p>	x = simple_strtoul(buf, NULL, 0);</p>
<p>	if (check_zero &#038;&#038; !x)<br />
		return -EINVAL;</p>
<p>	*cl_field = x;<br />
	*info_field = x;</p>
<p>	return len;<br />
}</p>
<p>#define CLUSTER_ATTR(name, check_zero)                                        \<br />
static ssize_t name##_write(struct dlm_cluster *cl, const char *buf, size_t len) \<br />
{                                                                             \<br />
	return cluster_set(cl, &#038;cl->cl_##name, &#038;dlm_config.ci_##name,         \<br />
			   check_zero, buf, len);                             \<br />
}                                                                             \<br />
static ssize_t name##_read(struct dlm_cluster *cl, char *buf)                 \<br />
{                                                                             \<br />
	return snprintf(buf, PAGE_SIZE, &laquo;%u\n&raquo;, cl->cl_##name);               \<br />
}                                                                             \<br />
static struct cluster_attribute cluster_attr_##name =                         \<br />
__CONFIGFS_ATTR(name, 0644, name##_read, name##_write)</p>
<p>CLUSTER_ATTR(tcp_port, 1);<br />
CLUSTER_ATTR(buffer_size, 1);<br />
CLUSTER_ATTR(rsbtbl_size, 1);<br />
CLUSTER_ATTR(lkbtbl_size, 1);<br />
CLUSTER_ATTR(dirtbl_size, 1);<br />
CLUSTER_ATTR(recover_timer, 1);<br />
CLUSTER_ATTR(toss_secs, 1);<br />
CLUSTER_ATTR(scan_secs, 1);<br />
CLUSTER_ATTR(log_debug, 0);<br />
CLUSTER_ATTR(protocol, 0);<br />
CLUSTER_ATTR(timewarn_cs, 1);</p>
<p>static struct configfs_attribute *cluster_attrs[] = {<br />
	[CLUSTER_ATTR_TCP_PORT] = &#038;cluster_attr_tcp_port.attr,<br />
	[CLUSTER_ATTR_BUFFER_SIZE] = &#038;cluster_attr_buffer_size.attr,<br />
	[CLUSTER_ATTR_RSBTBL_SIZE] = &#038;cluster_attr_rsbtbl_size.attr,<br />
	[CLUSTER_ATTR_LKBTBL_SIZE] = &#038;cluster_attr_lkbtbl_size.attr,<br />
	[CLUSTER_ATTR_DIRTBL_SIZE] = &#038;cluster_attr_dirtbl_size.attr,<br />
	[CLUSTER_ATTR_RECOVER_TIMER] = &#038;cluster_attr_recover_timer.attr,<br />
	[CLUSTER_ATTR_TOSS_SECS] = &#038;cluster_attr_toss_secs.attr,<br />
	[CLUSTER_ATTR_SCAN_SECS] = &#038;cluster_attr_scan_secs.attr,<br />
	[CLUSTER_ATTR_LOG_DEBUG] = &#038;cluster_attr_log_debug.attr,<br />
	[CLUSTER_ATTR_PROTOCOL] = &#038;cluster_attr_protocol.attr,<br />
	[CLUSTER_ATTR_TIMEWARN_CS] = &#038;cluster_attr_timewarn_cs.attr,<br />
	NULL,<br />
};</p>
<p>enum {<br />
	COMM_ATTR_NODEID = 0,<br />
	COMM_ATTR_LOCAL,<br />
	COMM_ATTR_ADDR,<br />
};</p>
<p>struct comm_attribute {<br />
	struct configfs_attribute attr;<br />
	ssize_t (*show)(struct dlm_comm *, char *);<br />
	ssize_t (*store)(struct dlm_comm *, const char *, size_t);<br />
};</p>
<p>static struct comm_attribute comm_attr_nodeid = {<br />
	.attr   = { .ca_owner = THIS_MODULE,<br />
                    .ca_name = &laquo;nodeid&raquo;,<br />
                    .ca_mode = S_IRUGO | S_IWUSR },<br />
	.show   = comm_nodeid_read,<br />
	.store  = comm_nodeid_write,<br />
};</p>
<p>static struct comm_attribute comm_attr_local = {<br />
	.attr   = { .ca_owner = THIS_MODULE,<br />
                    .ca_name = &laquo;local&raquo;,<br />
                    .ca_mode = S_IRUGO | S_IWUSR },<br />
	.show   = comm_local_read,<br />
	.store  = comm_local_write,<br />
};</p>
<p>static struct comm_attribute comm_attr_addr = {<br />
	.attr   = { .ca_owner = THIS_MODULE,<br />
                    .ca_name = &laquo;addr&raquo;,<br />
                    .ca_mode = S_IRUGO | S_IWUSR },<br />
	.store  = comm_addr_write,<br />
};</p>
<p>static struct configfs_attribute *comm_attrs[] = {<br />
	[COMM_ATTR_NODEID] = &#038;comm_attr_nodeid.attr,<br />
	[COMM_ATTR_LOCAL] = &#038;comm_attr_local.attr,<br />
	[COMM_ATTR_ADDR] = &#038;comm_attr_addr.attr,<br />
	NULL,<br />
};</p>
<p>enum {<br />
	NODE_ATTR_NODEID = 0,<br />
	NODE_ATTR_WEIGHT,<br />
};</p>
<p>struct node_attribute {<br />
	struct configfs_attribute attr;<br />
	ssize_t (*show)(struct dlm_node *, char *);<br />
	ssize_t (*store)(struct dlm_node *, const char *, size_t);<br />
};</p>
<p>static struct node_attribute node_attr_nodeid = {<br />
	.attr   = { .ca_owner = THIS_MODULE,<br />
                    .ca_name = &laquo;nodeid&raquo;,<br />
                    .ca_mode = S_IRUGO | S_IWUSR },<br />
	.show   = node_nodeid_read,<br />
	.store  = node_nodeid_write,<br />
};</p>
<p>static struct node_attribute node_attr_weight = {<br />
	.attr   = { .ca_owner = THIS_MODULE,<br />
                    .ca_name = &laquo;weight&raquo;,<br />
                    .ca_mode = S_IRUGO | S_IWUSR },<br />
	.show   = node_weight_read,<br />
	.store  = node_weight_write,<br />
};</p>
<p>static struct configfs_attribute *node_attrs[] = {<br />
	[NODE_ATTR_NODEID] = &#038;node_attr_nodeid.attr,<br />
	[NODE_ATTR_WEIGHT] = &#038;node_attr_weight.attr,<br />
	NULL,<br />
};</p>
<p>struct dlm_clusters {<br />
	struct configfs_subsystem subsys;<br />
};</p>
<p>struct dlm_spaces {<br />
	struct config_group ss_group;<br />
};</p>
<p>struct dlm_space {<br />
	struct config_group group;<br />
	struct list_head members;<br />
	struct mutex members_lock;<br />
	int members_count;<br />
};</p>
<p>struct dlm_comms {<br />
	struct config_group cs_group;<br />
};</p>
<p>struct dlm_comm {<br />
	struct config_item item;<br />
	int nodeid;<br />
	int local;<br />
	int addr_count;<br />
	struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];<br />
};</p>
<p>struct dlm_nodes {<br />
	struct config_group ns_group;<br />
};</p>
<p>struct dlm_node {<br />
	struct config_item item;<br />
	struct list_head list; /* space->members */<br />
	int nodeid;<br />
	int weight;<br />
	int new;<br />
};</p>
<p>static struct configfs_group_operations clusters_ops = {<br />
	.make_group = make_cluster,<br />
	.drop_item = drop_cluster,<br />
};</p>
<p>static struct configfs_item_operations cluster_ops = {<br />
	.release = release_cluster,<br />
	.show_attribute = show_cluster,<br />
	.store_attribute = store_cluster,<br />
};</p>
<p>static struct configfs_group_operations spaces_ops = {<br />
	.make_group = make_space,<br />
	.drop_item = drop_space,<br />
};</p>
<p>static struct configfs_item_operations space_ops = {<br />
	.release = release_space,<br />
};</p>
<p>static struct configfs_group_operations comms_ops = {<br />
	.make_item = make_comm,<br />
	.drop_item = drop_comm,<br />
};</p>
<p>static struct configfs_item_operations comm_ops = {<br />
	.release = release_comm,<br />
	.show_attribute = show_comm,<br />
	.store_attribute = store_comm,<br />
};</p>
<p>static struct configfs_group_operations nodes_ops = {<br />
	.make_item = make_node,<br />
	.drop_item = drop_node,<br />
};</p>
<p>static struct configfs_item_operations node_ops = {<br />
	.release = release_node,<br />
	.show_attribute = show_node,<br />
	.store_attribute = store_node,<br />
};</p>
<p>static struct config_item_type clusters_type = {<br />
	.ct_group_ops = &#038;clusters_ops,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type cluster_type = {<br />
	.ct_item_ops = &#038;cluster_ops,<br />
	.ct_attrs = cluster_attrs,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type spaces_type = {<br />
	.ct_group_ops = &#038;spaces_ops,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type space_type = {<br />
	.ct_item_ops = &#038;space_ops,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type comms_type = {<br />
	.ct_group_ops = &#038;comms_ops,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type comm_type = {<br />
	.ct_item_ops = &#038;comm_ops,<br />
	.ct_attrs = comm_attrs,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type nodes_type = {<br />
	.ct_group_ops = &#038;nodes_ops,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct config_item_type node_type = {<br />
	.ct_item_ops = &#038;node_ops,<br />
	.ct_attrs = node_attrs,<br />
	.ct_owner = THIS_MODULE,<br />
};</p>
<p>static struct dlm_cluster *config_item_to_cluster(struct config_item *i)<br />
{<br />
	return i ? container_of(to_config_group(i), struct dlm_cluster, group) :<br />
		   NULL;<br />
}</p>
<p>static struct dlm_space *config_item_to_space(struct config_item *i)<br />
{<br />
	return i ? container_of(to_config_group(i), struct dlm_space, group) :<br />
		   NULL;<br />
}</p>
<p>static struct dlm_comm *config_item_to_comm(struct config_item *i)<br />
{<br />
	return i ? container_of(i, struct dlm_comm, item) : NULL;<br />
}</p>
<p>static struct dlm_node *config_item_to_node(struct config_item *i)<br />
{<br />
	return i ? container_of(i, struct dlm_node, item) : NULL;<br />
}</p>
<p>static struct config_group *make_cluster(struct config_group *g,<br />
					 const char *name)<br />
{<br />
	struct dlm_cluster *cl = NULL;<br />
	struct dlm_spaces *sps = NULL;<br />
	struct dlm_comms *cms = NULL;<br />
	void *gps = NULL;</p>
<p>	cl = kzalloc(sizeof(struct dlm_cluster), GFP_KERNEL);<br />
	gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);<br />
	sps = kzalloc(sizeof(struct dlm_spaces), GFP_KERNEL);<br />
	cms = kzalloc(sizeof(struct dlm_comms), GFP_KERNEL);</p>
<p>	if (!cl || !gps || !sps || !cms)<br />
		goto fail;</p>
<p>	config_group_init_type_name(&#038;cl->group, name, &#038;cluster_type);<br />
	config_group_init_type_name(&#038;sps->ss_group, &laquo;spaces&raquo;, &#038;spaces_type);<br />
	config_group_init_type_name(&#038;cms->cs_group, &laquo;comms&raquo;, &#038;comms_type);</p>
<p>	cl->group.default_groups = gps;<br />
	cl->group.default_groups[0] = &#038;sps->ss_group;<br />
	cl->group.default_groups[1] = &#038;cms->cs_group;<br />
	cl->group.default_groups[2] = NULL;</p>
<p>	cl->cl_tcp_port = dlm_config.ci_tcp_port;<br />
	cl->cl_buffer_size = dlm_config.ci_buffer_size;<br />
	cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size;<br />
	cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size;<br />
	cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size;<br />
	cl->cl_recover_timer = dlm_config.ci_recover_timer;<br />
	cl->cl_toss_secs = dlm_config.ci_toss_secs;<br />
	cl->cl_scan_secs = dlm_config.ci_scan_secs;<br />
	cl->cl_log_debug = dlm_config.ci_log_debug;<br />
	cl->cl_protocol = dlm_config.ci_protocol;<br />
	cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs;</p>
<p>	space_list = &#038;sps->ss_group;<br />
	comm_list = &#038;cms->cs_group;<br />
	return &#038;cl->group;</p>
<p> fail:<br />
	kfree(cl);<br />
	kfree(gps);<br />
	kfree(sps);<br />
	kfree(cms);<br />
	return ERR_PTR(-ENOMEM);<br />
}</p>
<p>static void drop_cluster(struct config_group *g, struct config_item *i)<br />
{<br />
	struct dlm_cluster *cl = config_item_to_cluster(i);<br />
	struct config_item *tmp;<br />
	int j;</p>
<p>	for (j = 0; cl->group.default_groups[j]; j++) {<br />
		tmp = &#038;cl->group.default_groups[j]->cg_item;<br />
		cl->group.default_groups[j] = NULL;<br />
		config_item_put(tmp);<br />
	}</p>
<p>	space_list = NULL;<br />
	comm_list = NULL;</p>
<p>	config_item_put(i);<br />
}</p>
<p>static void release_cluster(struct config_item *i)<br />
{<br />
	struct dlm_cluster *cl = config_item_to_cluster(i);<br />
	kfree(cl->group.default_groups);<br />
	kfree(cl);<br />
}</p>
<p>static struct config_group *make_space(struct config_group *g, const char *name)<br />
{<br />
	struct dlm_space *sp = NULL;<br />
	struct dlm_nodes *nds = NULL;<br />
	void *gps = NULL;</p>
<p>	sp = kzalloc(sizeof(struct dlm_space), GFP_KERNEL);<br />
	gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL);<br />
	nds = kzalloc(sizeof(struct dlm_nodes), GFP_KERNEL);</p>
<p>	if (!sp || !gps || !nds)<br />
		goto fail;</p>
<p>	config_group_init_type_name(&#038;sp->group, name, &#038;space_type);<br />
	config_group_init_type_name(&#038;nds->ns_group, &laquo;nodes&raquo;, &#038;nodes_type);</p>
<p>	sp->group.default_groups = gps;<br />
	sp->group.default_groups[0] = &#038;nds->ns_group;<br />
	sp->group.default_groups[1] = NULL;</p>
<p>	INIT_LIST_HEAD(&#038;sp->members);<br />
	mutex_init(&#038;sp->members_lock);<br />
	sp->members_count = 0;<br />
	return &#038;sp->group;</p>
<p> fail:<br />
	kfree(sp);<br />
	kfree(gps);<br />
	kfree(nds);<br />
	return ERR_PTR(-ENOMEM);<br />
}</p>
<p>static void drop_space(struct config_group *g, struct config_item *i)<br />
{<br />
	struct dlm_space *sp = config_item_to_space(i);<br />
	struct config_item *tmp;<br />
	int j;</p>
<p>	/* assert list_empty(&#038;sp->members) */</p>
<p>	for (j = 0; sp->group.default_groups[j]; j++) {<br />
		tmp = &#038;sp->group.default_groups[j]->cg_item;<br />
		sp->group.default_groups[j] = NULL;<br />
		config_item_put(tmp);<br />
	}</p>
<p>	config_item_put(i);<br />
}</p>
<p>static void release_space(struct config_item *i)<br />
{<br />
	struct dlm_space *sp = config_item_to_space(i);<br />
	kfree(sp->group.default_groups);<br />
	kfree(sp);<br />
}</p>
<p>static struct config_item *make_comm(struct config_group *g, const char *name)<br />
{<br />
	struct dlm_comm *cm;</p>
<p>	cm = kzalloc(sizeof(struct dlm_comm), GFP_KERNEL);<br />
	if (!cm)<br />
		return ERR_PTR(-ENOMEM);</p>
<p>	config_item_init_type_name(&#038;cm->item, name, &#038;comm_type);<br />
	cm->nodeid = -1;<br />
	cm->local = 0;<br />
	cm->addr_count = 0;<br />
	return &#038;cm->item;<br />
}</p>
<p>static void drop_comm(struct config_group *g, struct config_item *i)<br />
{<br />
	struct dlm_comm *cm = config_item_to_comm(i);<br />
	if (local_comm == cm)<br />
		local_comm = NULL;<br />
	dlm_lowcomms_close(cm->nodeid);<br />
	while (cm->addr_count&#8211;)<br />
		kfree(cm->addr[cm->addr_count]);<br />
	config_item_put(i);<br />
}</p>
<p>static void release_comm(struct config_item *i)<br />
{<br />
	struct dlm_comm *cm = config_item_to_comm(i);<br />
	kfree(cm);<br />
}</p>
<p>static struct config_item *make_node(struct config_group *g, const char *name)<br />
{<br />
	struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);<br />
	struct dlm_node *nd;</p>
<p>	nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL);<br />
	if (!nd)<br />
		return ERR_PTR(-ENOMEM);</p>
<p>	config_item_init_type_name(&#038;nd->item, name, &#038;node_type);<br />
	nd->nodeid = -1;<br />
	nd->weight = 1;  /* default weight of 1 if none is set */<br />
	nd->new = 1;     /* set to 0 once it&#8217;s been read by dlm_nodeid_list() */</p>
<p>	mutex_lock(&#038;sp->members_lock);<br />
	list_add(&#038;nd->list, &#038;sp->members);<br />
	sp->members_count++;<br />
	mutex_unlock(&#038;sp->members_lock);</p>
<p>	return &#038;nd->item;<br />
}</p>
<p>static void drop_node(struct config_group *g, struct config_item *i)<br />
{<br />
	struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);<br />
	struct dlm_node *nd = config_item_to_node(i);</p>
<p>	mutex_lock(&#038;sp->members_lock);<br />
	list_del(&#038;nd->list);<br />
	sp->members_count&#8211;;<br />
	mutex_unlock(&#038;sp->members_lock);</p>
<p>	config_item_put(i);<br />
}</p>
<p>static void release_node(struct config_item *i)<br />
{<br />
	struct dlm_node *nd = config_item_to_node(i);<br />
	kfree(nd);<br />
}</p>
<p>static struct dlm_clusters clusters_root = {<br />
	.subsys = {<br />
		.su_group = {<br />
			.cg_item = {<br />
				.ci_namebuf = &laquo;dlm&raquo;,<br />
				.ci_type = &#038;clusters_type,<br />
			},<br />
		},<br />
	},<br />
};</p>
<p>int __init dlm_config_init(void)<br />
{<br />
	config_group_init(&#038;clusters_root.subsys.su_group);<br />
	mutex_init(&#038;clusters_root.subsys.su_mutex);<br />
	return configfs_register_subsystem(&#038;clusters_root.subsys);<br />
}</p>
<p>void dlm_config_exit(void)<br />
{<br />
	configfs_unregister_subsystem(&#038;clusters_root.subsys);<br />
}</p>
<p>/*<br />
 * Functions for user space to read/write attributes<br />
 */</p>
<p>static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,<br />
			    char *buf)<br />
{<br />
	struct dlm_cluster *cl = config_item_to_cluster(i);<br />
	struct cluster_attribute *cla =<br />
			container_of(a, struct cluster_attribute, attr);<br />
	return cla->show ? cla->show(cl, buf) : 0;<br />
}</p>
<p>static ssize_t store_cluster(struct config_item *i,<br />
			     struct configfs_attribute *a,<br />
			     const char *buf, size_t len)<br />
{<br />
	struct dlm_cluster *cl = config_item_to_cluster(i);<br />
	struct cluster_attribute *cla =<br />
		container_of(a, struct cluster_attribute, attr);<br />
	return cla->store ? cla->store(cl, buf, len) : -EINVAL;<br />
}</p>
<p>static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,<br />
			 char *buf)<br />
{<br />
	struct dlm_comm *cm = config_item_to_comm(i);<br />
	struct comm_attribute *cma =<br />
			container_of(a, struct comm_attribute, attr);<br />
	return cma->show ? cma->show(cm, buf) : 0;<br />
}</p>
<p>static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,<br />
			  const char *buf, size_t len)<br />
{<br />
	struct dlm_comm *cm = config_item_to_comm(i);<br />
	struct comm_attribute *cma =<br />
		container_of(a, struct comm_attribute, attr);<br />
	return cma->store ? cma->store(cm, buf, len) : -EINVAL;<br />
}</p>
<p>static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf)<br />
{<br />
	return sprintf(buf, &laquo;%d\n&raquo;, cm->nodeid);<br />
}</p>
<p>static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf,<br />
				 size_t len)<br />
{<br />
	cm->nodeid = simple_strtol(buf, NULL, 0);<br />
	return len;<br />
}</p>
<p>static ssize_t comm_local_read(struct dlm_comm *cm, char *buf)<br />
{<br />
	return sprintf(buf, &laquo;%d\n&raquo;, cm->local);<br />
}</p>
<p>static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,<br />
				size_t len)<br />
{<br />
	cm->local= simple_strtol(buf, NULL, 0);<br />
	if (cm->local &#038;&#038; !local_comm)<br />
		local_comm = cm;<br />
	return len;<br />
}</p>
<p>static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)<br />
{<br />
	struct sockaddr_storage *addr;</p>
<p>	if (len != sizeof(struct sockaddr_storage))<br />
		return -EINVAL;</p>
<p>	if (cm->addr_count >= DLM_MAX_ADDR_COUNT)<br />
		return -ENOSPC;</p>
<p>	addr = kzalloc(sizeof(*addr), GFP_KERNEL);<br />
	if (!addr)<br />
		return -ENOMEM;</p>
<p>	memcpy(addr, buf, len);<br />
	cm->addr[cm->addr_count++] = addr;<br />
	return len;<br />
}</p>
<p>static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,<br />
			 char *buf)<br />
{<br />
	struct dlm_node *nd = config_item_to_node(i);<br />
	struct node_attribute *nda =<br />
			container_of(a, struct node_attribute, attr);<br />
	return nda->show ? nda->show(nd, buf) : 0;<br />
}</p>
<p>static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,<br />
			  const char *buf, size_t len)<br />
{<br />
	struct dlm_node *nd = config_item_to_node(i);<br />
	struct node_attribute *nda =<br />
		container_of(a, struct node_attribute, attr);<br />
	return nda->store ? nda->store(nd, buf, len) : -EINVAL;<br />
}</p>
<p>static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf)<br />
{<br />
	return sprintf(buf, &laquo;%d\n&raquo;, nd->nodeid);<br />
}</p>
<p>static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,<br />
				 size_t len)<br />
{<br />
	nd->nodeid = simple_strtol(buf, NULL, 0);<br />
	return len;<br />
}</p>
<p>static ssize_t node_weight_read(struct dlm_node *nd, char *buf)<br />
{<br />
	return sprintf(buf, &laquo;%d\n&raquo;, nd->weight);<br />
}</p>
<p>static ssize_t node_weight_write(struct dlm_node *nd, const char *buf,<br />
				 size_t len)<br />
{<br />
	nd->weight = simple_strtol(buf, NULL, 0);<br />
	return len;<br />
}</p>
<p>/*<br />
 * Functions for the dlm to get the info that&#8217;s been configured<br />
 */</p>
<p>static struct dlm_space *get_space(char *name)<br />
{<br />
	struct config_item *i;</p>
<p>	if (!space_list)<br />
		return NULL;</p>
<p>	mutex_lock(&#038;space_list->cg_subsys->su_mutex);<br />
	i = config_group_find_item(space_list, name);<br />
	mutex_unlock(&#038;space_list->cg_subsys->su_mutex);</p>
<p>	return config_item_to_space(i);<br />
}</p>
<p>static void put_space(struct dlm_space *sp)<br />
{<br />
	config_item_put(&#038;sp->group.cg_item);<br />
}</p>
<p>static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)<br />
{<br />
	switch (x->ss_family) {<br />
	case AF_INET: {<br />
		struct sockaddr_in *sinx = (struct sockaddr_in *)x;<br />
		struct sockaddr_in *siny = (struct sockaddr_in *)y;<br />
		if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)<br />
			return 0;<br />
		if (sinx->sin_port != siny->sin_port)<br />
			return 0;<br />
		break;<br />
	}<br />
	case AF_INET6: {<br />
		struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;<br />
		struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;<br />
		if (!ipv6_addr_equal(&#038;sinx->sin6_addr, &#038;siny->sin6_addr))<br />
			return 0;<br />
		if (sinx->sin6_port != siny->sin6_port)<br />
			return 0;<br />
		break;<br />
	}<br />
	default:<br />
		return 0;<br />
	}<br />
	return 1;<br />
}</p>
<p>static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)<br />
{<br />
	struct config_item *i;<br />
	struct dlm_comm *cm = NULL;<br />
	int found = 0;</p>
<p>	if (!comm_list)<br />
		return NULL;</p>
<p>	mutex_lock(&#038;clusters_root.subsys.su_mutex);</p>
<p>	list_for_each_entry(i, &#038;comm_list->cg_children, ci_entry) {<br />
		cm = config_item_to_comm(i);</p>
<p>		if (nodeid) {<br />
			if (cm->nodeid != nodeid)<br />
				continue;<br />
			found = 1;<br />
			config_item_get(i);<br />
			break;<br />
		} else {<br />
			if (!cm->addr_count || !addr_compare(cm->addr[0], addr))<br />
				continue;<br />
			found = 1;<br />
			config_item_get(i);<br />
			break;<br />
		}<br />
	}<br />
	mutex_unlock(&#038;clusters_root.subsys.su_mutex);</p>
<p>	if (!found)<br />
		cm = NULL;<br />
	return cm;<br />
}</p>
<p>static void put_comm(struct dlm_comm *cm)<br />
{<br />
	config_item_put(&#038;cm->item);<br />
}</p>
<p>/* caller must free mem */<br />
int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,<br />
		    int **new_out, int *new_count_out)<br />
{<br />
	struct dlm_space *sp;<br />
	struct dlm_node *nd;<br />
	int i = 0, rv = 0, ids_count = 0, new_count = 0;<br />
	int *ids, *new;</p>
<p>	sp = get_space(lsname);<br />
	if (!sp)<br />
		return -EEXIST;</p>
<p>	mutex_lock(&#038;sp->members_lock);<br />
	if (!sp->members_count) {<br />
		rv = -EINVAL;<br />
		printk(KERN_ERR &laquo;dlm: zero members_count\n&raquo;);<br />
		goto out;<br />
	}</p>
<p>	ids_count = sp->members_count;</p>
<p>	ids = kcalloc(ids_count, sizeof(int), GFP_KERNEL);<br />
	if (!ids) {<br />
		rv = -ENOMEM;<br />
		goto out;<br />
	}</p>
<p>	list_for_each_entry(nd, &#038;sp->members, list) {<br />
		ids[i++] = nd->nodeid;<br />
		if (nd->new)<br />
			new_count++;<br />
	}</p>
<p>	if (ids_count != i)<br />
		printk(KERN_ERR &laquo;dlm: bad nodeid count %d %d\n&raquo;, ids_count, i);</p>
<p>	if (!new_count)<br />
		goto out_ids;</p>
<p>	new = kcalloc(new_count, sizeof(int), GFP_KERNEL);<br />
	if (!new) {<br />
		kfree(ids);<br />
		rv = -ENOMEM;<br />
		goto out;<br />
	}</p>
<p>	i = 0;<br />
	list_for_each_entry(nd, &#038;sp->members, list) {<br />
		if (nd->new) {<br />
			new[i++] = nd->nodeid;<br />
			nd->new = 0;<br />
		}<br />
	}<br />
	*new_count_out = new_count;<br />
	*new_out = new;</p>
<p> out_ids:<br />
	*ids_count_out = ids_count;<br />
	*ids_out = ids;<br />
 out:<br />
	mutex_unlock(&#038;sp->members_lock);<br />
	put_space(sp);<br />
	return rv;<br />
}</p>
<p>int dlm_node_weight(char *lsname, int nodeid)<br />
{<br />
	struct dlm_space *sp;<br />
	struct dlm_node *nd;<br />
	int w = -EEXIST;</p>
<p>	sp = get_space(lsname);<br />
	if (!sp)<br />
		goto out;</p>
<p>	mutex_lock(&#038;sp->members_lock);<br />
	list_for_each_entry(nd, &#038;sp->members, list) {<br />
		if (nd->nodeid != nodeid)<br />
			continue;<br />
		w = nd->weight;<br />
		break;<br />
	}<br />
	mutex_unlock(&#038;sp->members_lock);<br />
	put_space(sp);<br />
 out:<br />
	return w;<br />
}</p>
<p>int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)<br />
{<br />
	struct dlm_comm *cm = get_comm(nodeid, NULL);<br />
	if (!cm)<br />
		return -EEXIST;<br />
	if (!cm->addr_count)<br />
		return -ENOENT;<br />
	memcpy(addr, cm->addr[0], sizeof(*addr));<br />
	put_comm(cm);<br />
	return 0;<br />
}</p>
<p>int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)<br />
{<br />
	struct dlm_comm *cm = get_comm(0, addr);<br />
	if (!cm)<br />
		return -EEXIST;<br />
	*nodeid = cm->nodeid;<br />
	put_comm(cm);<br />
	return 0;<br />
}</p>
<p>int dlm_our_nodeid(void)<br />
{<br />
	return local_comm ? local_comm->nodeid : 0;<br />
}</p>
<p>/* num 0 is first addr, num 1 is second addr */<br />
int dlm_our_addr(struct sockaddr_storage *addr, int num)<br />
{<br />
	if (!local_comm)<br />
		return -1;<br />
	if (num + 1 > local_comm->addr_count)<br />
		return -1;<br />
	memcpy(addr, local_comm->addr[num], sizeof(*addr));<br />
	return 0;<br />
}</p>
<p>/* Config file defaults */<br />
#define DEFAULT_TCP_PORT       21064<br />
#define DEFAULT_BUFFER_SIZE     4096<br />
#define DEFAULT_RSBTBL_SIZE      256<br />
#define DEFAULT_LKBTBL_SIZE     1024<br />
#define DEFAULT_DIRTBL_SIZE      512<br />
#define DEFAULT_RECOVER_TIMER      5<br />
#define DEFAULT_TOSS_SECS         10<br />
#define DEFAULT_SCAN_SECS          5<br />
#define DEFAULT_LOG_DEBUG          0<br />
#define DEFAULT_PROTOCOL           0<br />
#define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */</p>
<p>struct dlm_config_info dlm_config = {<br />
	.ci_tcp_port = DEFAULT_TCP_PORT,<br />
	.ci_buffer_size = DEFAULT_BUFFER_SIZE,<br />
	.ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE,<br />
	.ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE,<br />
	.ci_dirtbl_size = DEFAULT_DIRTBL_SIZE,<br />
	.ci_recover_timer = DEFAULT_RECOVER_TIMER,<br />
	.ci_toss_secs = DEFAULT_TOSS_SECS,<br />
	.ci_scan_secs = DEFAULT_SCAN_SECS,<br />
	.ci_log_debug = DEFAULT_LOG_DEBUG,<br />
	.ci_protocol = DEFAULT_PROTOCOL,<br />
	.ci_timewarn_cs = DEFAULT_TIMEWARN_CS<br />
};</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/config-c-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ast.h</title>
		<link>http://lynyrd.ru/ast-h</link>
		<comments>http://lynyrd.ru/ast-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:47:17 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/ast-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#ifndef __ASTD_DOT_H__
#define __ASTD_DOT_H__
void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode);
void dlm_del_ast(struct dlm_lkb ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.<span id="more-1019"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __ASTD_DOT_H__<br />
#define __ASTD_DOT_H__</p>
<p>void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode);<br />
void dlm_del_ast(struct dlm_lkb *lkb);</p>
<p>void dlm_astd_wake(void);<br />
int dlm_astd_start(void);<br />
void dlm_astd_stop(void);<br />
void dlm_astd_suspend(void);<br />
void dlm_astd_resume(void);</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/ast-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ast.c</title>
		<link>http://lynyrd.ru/ast-c</link>
		<comments>http://lynyrd.ru/ast-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:46:58 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1017</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2008 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 ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1017"></span><br />
**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;user.h&raquo;<br />
#include &laquo;ast.h&raquo;</p>
<p>#define WAKE_ASTS  0</p>
<p>static struct list_head		ast_queue;<br />
static spinlock_t		ast_queue_lock;<br />
static struct task_struct *	astd_task;<br />
static unsigned long		astd_wakeflags;<br />
static struct mutex		astd_running;</p>
<p>void dlm_del_ast(struct dlm_lkb *lkb)<br />
{<br />
	spin_lock(&#038;ast_queue_lock);<br />
	if (lkb->lkb_ast_type &#038; (AST_COMP | AST_BAST))<br />
		list_del(&#038;lkb->lkb_astqueue);<br />
	spin_unlock(&#038;ast_queue_lock);<br />
}</p>
<p>void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode)<br />
{<br />
	if (lkb->lkb_flags &#038; DLM_IFL_USER) {<br />
		dlm_user_add_ast(lkb, type, bastmode);<br />
		return;<br />
	}</p>
<p>	spin_lock(&#038;ast_queue_lock);<br />
	if (!(lkb->lkb_ast_type &#038; (AST_COMP | AST_BAST))) {<br />
		kref_get(&#038;lkb->lkb_ref);<br />
		list_add_tail(&#038;lkb->lkb_astqueue, &#038;ast_queue);<br />
	}<br />
	lkb->lkb_ast_type |= type;<br />
	if (bastmode)<br />
		lkb->lkb_bastmode = bastmode;<br />
	spin_unlock(&#038;ast_queue_lock);</p>
<p>	set_bit(WAKE_ASTS, &#038;astd_wakeflags);<br />
	wake_up_process(astd_task);<br />
}</p>
<p>static void process_asts(void)<br />
{<br />
	struct dlm_ls *ls = NULL;<br />
	struct dlm_rsb *r = NULL;<br />
	struct dlm_lkb *lkb;<br />
	void (*cast) (void *astparam);<br />
	void (*bast) (void *astparam, int mode);<br />
	int type = 0, bastmode;</p>
<p>repeat:<br />
	spin_lock(&#038;ast_queue_lock);<br />
	list_for_each_entry(lkb, &#038;ast_queue, lkb_astqueue) {<br />
		r = lkb->lkb_resource;<br />
		ls = r->res_ls;</p>
<p>		if (dlm_locking_stopped(ls))<br />
			continue;</p>
<p>		list_del(&#038;lkb->lkb_astqueue);<br />
		type = lkb->lkb_ast_type;<br />
		lkb->lkb_ast_type = 0;<br />
		bastmode = lkb->lkb_bastmode;</p>
<p>		spin_unlock(&#038;ast_queue_lock);<br />
		cast = lkb->lkb_astfn;<br />
		bast = lkb->lkb_bastfn;</p>
<p>		if ((type &#038; AST_COMP) &#038;&#038; cast)<br />
			cast(lkb->lkb_astparam);</p>
<p>		if ((type &#038; AST_BAST) &#038;&#038; bast)<br />
			bast(lkb->lkb_astparam, bastmode);</p>
<p>		/* this removes the reference added by dlm_add_ast<br />
		   and may result in the lkb being freed */<br />
		dlm_put_lkb(lkb);</p>
<p>		cond_resched();<br />
		goto repeat;<br />
	}<br />
	spin_unlock(&#038;ast_queue_lock);<br />
}</p>
<p>static inline int no_asts(void)<br />
{<br />
	int ret;</p>
<p>	spin_lock(&#038;ast_queue_lock);<br />
	ret = list_empty(&#038;ast_queue);<br />
	spin_unlock(&#038;ast_queue_lock);<br />
	return ret;<br />
}</p>
<p>static int dlm_astd(void *data)<br />
{<br />
	while (!kthread_should_stop()) {<br />
		set_current_state(TASK_INTERRUPTIBLE);<br />
		if (!test_bit(WAKE_ASTS, &#038;astd_wakeflags))<br />
			schedule();<br />
		set_current_state(TASK_RUNNING);</p>
<p>		mutex_lock(&#038;astd_running);<br />
		if (test_and_clear_bit(WAKE_ASTS, &#038;astd_wakeflags))<br />
			process_asts();<br />
		mutex_unlock(&#038;astd_running);<br />
	}<br />
	return 0;<br />
}</p>
<p>void dlm_astd_wake(void)<br />
{<br />
	if (!no_asts()) {<br />
		set_bit(WAKE_ASTS, &#038;astd_wakeflags);<br />
		wake_up_process(astd_task);<br />
	}<br />
}</p>
<p>int dlm_astd_start(void)<br />
{<br />
	struct task_struct *p;<br />
	int error = 0;</p>
<p>	INIT_LIST_HEAD(&#038;ast_queue);<br />
	spin_lock_init(&#038;ast_queue_lock);<br />
	mutex_init(&#038;astd_running);</p>
<p>	p = kthread_run(dlm_astd, NULL, &laquo;dlm_astd&raquo;);<br />
	if (IS_ERR(p))<br />
		error = PTR_ERR(p);<br />
	else<br />
		astd_task = p;<br />
	return error;<br />
}</p>
<p>void dlm_astd_stop(void)<br />
{<br />
	kthread_stop(astd_task);<br />
}</p>
<p>void dlm_astd_suspend(void)<br />
{<br />
	mutex_lock(&#038;astd_running);<br />
}</p>
<p>void dlm_astd_resume(void)<br />
{<br />
	mutex_unlock(&#038;astd_running);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/ast-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>inode.c</title>
		<link>http://lynyrd.ru/inode-c-14</link>
		<comments>http://lynyrd.ru/inode-c-14#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:46:24 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1015</guid>
		<description><![CDATA[/*
 *  file.c &#8211; part of debugfs, a tiny little debug file system
 *
 *  Copyright (C) 2004 Greg Kroah-Hartman 
 *  Copyright (C) 2004 IBM Inc.
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License version
 *	2 as ]]></description>
			<content:encoded><![CDATA[<p>/*<br />
 *  file.c &#8211; part of debugfs, a tiny little debug file system<span id="more-1015"></span><br />
 *<br />
 *  Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com><br />
 *  Copyright (C) 2004 IBM Inc.<br />
 *<br />
 *	This program is free software; you can redistribute it and/or<br />
 *	modify it under the terms of the GNU General Public License version<br />
 *	2 as published by the Free Software Foundation.<br />
 *<br />
 *  debugfs is for people to use instead of /proc or /sys.<br />
 *  See Documentation/DocBook/kernel-api for more details.<br />
 *<br />
 */</p>
<p>/* uncomment to get debug messages from the debug filesystem, ah the irony. */<br />
/* #define DEBUG */</p>
<p>#include
<linux/module.h>
#include
<linux/fs.h>
#include
<linux/mount.h>
#include
<linux/pagemap.h>
#include
<linux/init.h>
#include
<linux/kobject.h>
#include
<linux/namei.h>
#include
<linux/debugfs.h>
#include
<linux/fsnotify.h>
#include
<linux/string.h>
#include
<linux/magic.h>
<p>static struct vfsmount *debugfs_mount;<br />
static int debugfs_mount_count;<br />
static bool debugfs_registered;</p>
<p>static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev,<br />
				       void *data, const struct file_operations *fops)</p>
<p>{<br />
	struct inode *inode = new_inode(sb);</p>
<p>	if (inode) {<br />
		inode->i_mode = mode;<br />
		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;<br />
		switch (mode &#038; S_IFMT) {<br />
		default:<br />
			init_special_inode(inode, mode, dev);<br />
			break;<br />
		case S_IFREG:<br />
			inode->i_fop = fops ? fops : &#038;debugfs_file_operations;<br />
			inode->i_private = data;<br />
			break;<br />
		case S_IFLNK:<br />
			inode->i_op = &#038;debugfs_link_operations;<br />
			inode->i_fop = fops;<br />
			inode->i_private = data;<br />
			break;<br />
		case S_IFDIR:<br />
			inode->i_op = &#038;simple_dir_inode_operations;<br />
			inode->i_fop = fops ? fops : &#038;simple_dir_operations;<br />
			inode->i_private = data;</p>
<p>			/* directory inodes start off with i_nlink == 2<br />
			 * (for &laquo;.&raquo; entry) */<br />
			inc_nlink(inode);<br />
			break;<br />
		}<br />
	}<br />
	return inode;<br />
}</p>
<p>/* SMP-safe */<br />
static int debugfs_mknod(struct inode *dir, struct dentry *dentry,<br />
			 int mode, dev_t dev, void *data,<br />
			 const struct file_operations *fops)<br />
{<br />
	struct inode *inode;<br />
	int error = -EPERM;</p>
<p>	if (dentry->d_inode)<br />
		return -EEXIST;</p>
<p>	inode = debugfs_get_inode(dir->i_sb, mode, dev, data, fops);<br />
	if (inode) {<br />
		d_instantiate(dentry, inode);<br />
		dget(dentry);<br />
		error = 0;<br />
	}<br />
	return error;<br />
}</p>
<p>static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode,<br />
			 void *data, const struct file_operations *fops)<br />
{<br />
	int res;</p>
<p>	mode = (mode &#038; (S_IRWXUGO | S_ISVTX)) | S_IFDIR;<br />
	res = debugfs_mknod(dir, dentry, mode, 0, data, fops);<br />
	if (!res) {<br />
		inc_nlink(dir);<br />
		fsnotify_mkdir(dir, dentry);<br />
	}<br />
	return res;<br />
}</p>
<p>static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode,<br />
			void *data, const struct file_operations *fops)<br />
{<br />
	mode = (mode &#038; S_IALLUGO) | S_IFLNK;<br />
	return debugfs_mknod(dir, dentry, mode, 0, data, fops);<br />
}</p>
<p>static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode,<br />
			  void *data, const struct file_operations *fops)<br />
{<br />
	int res;</p>
<p>	mode = (mode &#038; S_IALLUGO) | S_IFREG;<br />
	res = debugfs_mknod(dir, dentry, mode, 0, data, fops);<br />
	if (!res)<br />
		fsnotify_create(dir, dentry);<br />
	return res;<br />
}</p>
<p>static inline int debugfs_positive(struct dentry *dentry)<br />
{<br />
	return dentry->d_inode &#038;&#038; !d_unhashed(dentry);<br />
}</p>
<p>static int debug_fill_super(struct super_block *sb, void *data, int silent)<br />
{<br />
	static struct tree_descr debug_files[] = {{&raquo;"}};</p>
<p>	return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);<br />
}</p>
<p>static int debug_get_sb(struct file_system_type *fs_type,<br />
			int flags, const char *dev_name,<br />
			void *data, struct vfsmount *mnt)<br />
{<br />
	return get_sb_single(fs_type, flags, data, debug_fill_super, mnt);<br />
}</p>
<p>static struct file_system_type debug_fs_type = {<br />
	.owner =	THIS_MODULE,<br />
	.name =		&laquo;debugfs&raquo;,<br />
	.get_sb =	debug_get_sb,<br />
	.kill_sb =	kill_litter_super,<br />
};</p>
<p>static int debugfs_create_by_name(const char *name, mode_t mode,<br />
				  struct dentry *parent,<br />
				  struct dentry **dentry,<br />
				  void *data,<br />
				  const struct file_operations *fops)<br />
{<br />
	int error = 0;</p>
<p>	/* If the parent is not specified, we create it in the root.<br />
	 * We need the root dentry to do this, which is in the super<br />
	 * block. A pointer to that is in the struct vfsmount that we<br />
	 * have around.<br />
	 */<br />
	if (!parent) {<br />
		if (debugfs_mount &#038;&#038; debugfs_mount->mnt_sb) {<br />
			parent = debugfs_mount->mnt_sb->s_root;<br />
		}<br />
	}<br />
	if (!parent) {<br />
		pr_debug(&raquo;debugfs: Ah! can not find a parent!\n&raquo;);<br />
		return -EFAULT;<br />
	}</p>
<p>	*dentry = NULL;<br />
	mutex_lock(&#038;parent->d_inode->i_mutex);<br />
	*dentry = lookup_one_len(name, parent, strlen(name));<br />
	if (!IS_ERR(*dentry)) {<br />
		switch (mode &#038; S_IFMT) {<br />
		case S_IFDIR:<br />
			error = debugfs_mkdir(parent->d_inode, *dentry, mode,<br />
					      data, fops);<br />
			break;<br />
		case S_IFLNK:<br />
			error = debugfs_link(parent->d_inode, *dentry, mode,<br />
					     data, fops);<br />
			break;<br />
		default:<br />
			error = debugfs_create(parent->d_inode, *dentry, mode,<br />
					       data, fops);<br />
			break;<br />
		}<br />
		dput(*dentry);<br />
	} else<br />
		error = PTR_ERR(*dentry);<br />
	mutex_unlock(&#038;parent->d_inode->i_mutex);</p>
<p>	return error;<br />
}</p>
<p>/**<br />
 * debugfs_create_file &#8211; create a file in the debugfs filesystem<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this paramater is NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @data: a pointer to something that the caller will want to get to later<br />
 *        on.  The inode.i_private pointer will point to this value on<br />
 *        the open() call.<br />
 * @fops: a pointer to a struct file_operations that should be used for<br />
 *        this file.<br />
 *<br />
 * This is the basic &laquo;create a file&raquo; function for debugfs.  It allows for a<br />
 * wide range of flexibility in createing a file, or a directory (if you<br />
 * want to create a directory, the debugfs_create_dir() function is<br />
 * recommended to be used instead.)<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.<br />
 */<br />
struct dentry *debugfs_create_file(const char *name, mode_t mode,<br />
				   struct dentry *parent, void *data,<br />
				   const struct file_operations *fops)<br />
{<br />
	struct dentry *dentry = NULL;<br />
	int error;</p>
<p>	pr_debug(&raquo;debugfs: creating file &#8216;%s&#8217;\n&raquo;,name);</p>
<p>	error = simple_pin_fs(&#038;debug_fs_type, &#038;debugfs_mount,<br />
			      &#038;debugfs_mount_count);<br />
	if (error)<br />
		goto exit;</p>
<p>	error = debugfs_create_by_name(name, mode, parent, &#038;dentry,<br />
				       data, fops);<br />
	if (error) {<br />
		dentry = NULL;<br />
		simple_release_fs(&#038;debugfs_mount, &#038;debugfs_mount_count);<br />
		goto exit;<br />
	}<br />
exit:<br />
	return dentry;<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_file);</p>
<p>/**<br />
 * debugfs_create_dir &#8211; create a directory in the debugfs filesystem<br />
 * @name: a pointer to a string containing the name of the directory to<br />
 *        create.<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this paramater is NULL, then the<br />
 *          directory will be created in the root of the debugfs filesystem.<br />
 *<br />
 * This function creates a directory in debugfs with the given name.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.<br />
 */<br />
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)<br />
{<br />
	return debugfs_create_file(name,<br />
				   S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,<br />
				   parent, NULL, NULL);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_dir);</p>
<p>/**<br />
 * debugfs_create_symlink- create a symbolic link in the debugfs filesystem<br />
 * @name: a pointer to a string containing the name of the symbolic link to<br />
 *        create.<br />
 * @parent: a pointer to the parent dentry for this symbolic link.  This<br />
 *          should be a directory dentry if set.  If this paramater is NULL,<br />
 *          then the symbolic link will be created in the root of the debugfs<br />
 *          filesystem.<br />
 * @target: a pointer to a string containing the path to the target of the<br />
 *          symbolic link.<br />
 *<br />
 * This function creates a symbolic link with the given name in debugfs that<br />
 * links to the given target path.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the symbolic<br />
 * link is to be removed (no automatic cleanup happens if your module is<br />
 * unloaded, you are responsible here.)  If an error occurs, %NULL will be<br />
 * returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.<br />
 */<br />
struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,<br />
				      const char *target)<br />
{<br />
	struct dentry *result;<br />
	char *link;</p>
<p>	link = kstrdup(target, GFP_KERNEL);<br />
	if (!link)<br />
		return NULL;</p>
<p>	result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link,<br />
				     NULL);<br />
	if (!result)<br />
		kfree(link);<br />
	return result;<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_symlink);</p>
<p>static void __debugfs_remove(struct dentry *dentry, struct dentry *parent)<br />
{<br />
	int ret = 0;</p>
<p>	if (debugfs_positive(dentry)) {<br />
		if (dentry->d_inode) {<br />
			dget(dentry);<br />
			switch (dentry->d_inode->i_mode &#038; S_IFMT) {<br />
			case S_IFDIR:<br />
				ret = simple_rmdir(parent->d_inode, dentry);<br />
				break;<br />
			case S_IFLNK:<br />
				kfree(dentry->d_inode->i_private);<br />
				/* fall through */<br />
			default:<br />
				simple_unlink(parent->d_inode, dentry);<br />
				break;<br />
			}<br />
			if (!ret)<br />
				d_delete(dentry);<br />
			dput(dentry);<br />
		}<br />
	}<br />
}</p>
<p>/**<br />
 * debugfs_remove &#8211; removes a file or directory from the debugfs filesystem<br />
 * @dentry: a pointer to a the dentry of the file or directory to be<br />
 *          removed.<br />
 *<br />
 * This function removes a file or directory in debugfs that was previously<br />
 * created with a call to another debugfs function (like<br />
 * debugfs_create_file() or variants thereof.)<br />
 *<br />
 * This function is required to be called in order for the file to be<br />
 * removed, no automatic cleanup of files will happen when a module is<br />
 * removed, you are responsible here.<br />
 */<br />
void debugfs_remove(struct dentry *dentry)<br />
{<br />
	struct dentry *parent;</p>
<p>	if (!dentry)<br />
		return;</p>
<p>	parent = dentry->d_parent;<br />
	if (!parent || !parent->d_inode)<br />
		return;</p>
<p>	mutex_lock(&#038;parent->d_inode->i_mutex);<br />
	__debugfs_remove(dentry, parent);<br />
	mutex_unlock(&#038;parent->d_inode->i_mutex);<br />
	simple_release_fs(&#038;debugfs_mount, &#038;debugfs_mount_count);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_remove);</p>
<p>/**<br />
 * debugfs_remove_recursive &#8211; recursively removes a directory<br />
 * @dentry: a pointer to a the dentry of the directory to be removed.<br />
 *<br />
 * This function recursively removes a directory tree in debugfs that<br />
 * was previously created with a call to another debugfs function<br />
 * (like debugfs_create_file() or variants thereof.)<br />
 *<br />
 * This function is required to be called in order for the file to be<br />
 * removed, no automatic cleanup of files will happen when a module is<br />
 * removed, you are responsible here.<br />
 */<br />
void debugfs_remove_recursive(struct dentry *dentry)<br />
{<br />
	struct dentry *child;<br />
	struct dentry *parent;</p>
<p>	if (!dentry)<br />
		return;</p>
<p>	parent = dentry->d_parent;<br />
	if (!parent || !parent->d_inode)<br />
		return;</p>
<p>	parent = dentry;<br />
	mutex_lock(&#038;parent->d_inode->i_mutex);</p>
<p>	while (1) {<br />
		/*<br />
		 * When all dentries under &laquo;parent&raquo; has been removed,<br />
		 * walk up the tree until we reach our starting point.<br />
		 */<br />
		if (list_empty(&#038;parent->d_subdirs)) {<br />
			mutex_unlock(&#038;parent->d_inode->i_mutex);<br />
			if (parent == dentry)<br />
				break;<br />
			parent = parent->d_parent;<br />
			mutex_lock(&#038;parent->d_inode->i_mutex);<br />
		}<br />
		child = list_entry(parent->d_subdirs.next, struct dentry,<br />
				d_u.d_child);<br />
 next_sibling:</p>
<p>		/*<br />
		 * If &laquo;child&raquo; isn&#8217;t empty, walk down the tree and<br />
		 * remove all its descendants first.<br />
		 */<br />
		if (!list_empty(&#038;child->d_subdirs)) {<br />
			mutex_unlock(&#038;parent->d_inode->i_mutex);<br />
			parent = child;<br />
			mutex_lock(&#038;parent->d_inode->i_mutex);<br />
			continue;<br />
		}<br />
		__debugfs_remove(child, parent);<br />
		if (parent->d_subdirs.next == &#038;child->d_u.d_child) {<br />
			/*<br />
			 * Try the next sibling.<br />
			 */<br />
			if (child->d_u.d_child.next != &#038;parent->d_subdirs) {<br />
				child = list_entry(child->d_u.d_child.next,<br />
						   struct dentry,<br />
						   d_u.d_child);<br />
				goto next_sibling;<br />
			}</p>
<p>			/*<br />
			 * Avoid infinite loop if we fail to remove<br />
			 * one dentry.<br />
			 */<br />
			mutex_unlock(&#038;parent->d_inode->i_mutex);<br />
			break;<br />
		}<br />
		simple_release_fs(&#038;debugfs_mount, &#038;debugfs_mount_count);<br />
	}</p>
<p>	parent = dentry->d_parent;<br />
	mutex_lock(&#038;parent->d_inode->i_mutex);<br />
	__debugfs_remove(dentry, parent);<br />
	mutex_unlock(&#038;parent->d_inode->i_mutex);<br />
	simple_release_fs(&#038;debugfs_mount, &#038;debugfs_mount_count);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_remove_recursive);</p>
<p>/**<br />
 * debugfs_rename &#8211; rename a file/directory in the debugfs filesystem<br />
 * @old_dir: a pointer to the parent dentry for the renamed object. This<br />
 *          should be a directory dentry.<br />
 * @old_dentry: dentry of an object to be renamed.<br />
 * @new_dir: a pointer to the parent dentry where the object should be<br />
 *          moved. This should be a directory dentry.<br />
 * @new_name: a pointer to a string containing the target name.<br />
 *<br />
 * This function renames a file/directory in debugfs.  The target must not<br />
 * exist for rename to succeed.<br />
 *<br />
 * This function will return a pointer to old_dentry (which is updated to<br />
 * reflect renaming) if it succeeds. If an error occurs, %NULL will be<br />
 * returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.<br />
 */<br />
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,<br />
		struct dentry *new_dir, const char *new_name)<br />
{<br />
	int error;<br />
	struct dentry *dentry = NULL, *trap;<br />
	const char *old_name;</p>
<p>	trap = lock_rename(new_dir, old_dir);<br />
	/* Source or destination directories don&#8217;t exist? */<br />
	if (!old_dir->d_inode || !new_dir->d_inode)<br />
		goto exit;<br />
	/* Source does not exist, cyclic rename, or mountpoint? */<br />
	if (!old_dentry->d_inode || old_dentry == trap ||<br />
	    d_mountpoint(old_dentry))<br />
		goto exit;<br />
	dentry = lookup_one_len(new_name, new_dir, strlen(new_name));<br />
	/* Lookup failed, cyclic rename or target exists? */<br />
	if (IS_ERR(dentry) || dentry == trap || dentry->d_inode)<br />
		goto exit;</p>
<p>	old_name = fsnotify_oldname_init(old_dentry->d_name.name);</p>
<p>	error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode,<br />
		dentry);<br />
	if (error) {<br />
		fsnotify_oldname_free(old_name);<br />
		goto exit;<br />
	}<br />
	d_move(old_dentry, dentry);<br />
	fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,<br />
		old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode),<br />
		NULL, old_dentry);<br />
	fsnotify_oldname_free(old_name);<br />
	unlock_rename(new_dir, old_dir);<br />
	dput(dentry);<br />
	return old_dentry;<br />
exit:<br />
	if (dentry &#038;&#038; !IS_ERR(dentry))<br />
		dput(dentry);<br />
	unlock_rename(new_dir, old_dir);<br />
	return NULL;<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_rename);</p>
<p>/**<br />
 * debugfs_initialized &#8211; Tells whether debugfs has been registered<br />
 */<br />
bool debugfs_initialized(void)<br />
{<br />
	return debugfs_registered;<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_initialized);</p>
<p>static struct kobject *debug_kobj;</p>
<p>static int __init debugfs_init(void)<br />
{<br />
	int retval;</p>
<p>	debug_kobj = kobject_create_and_add(&raquo;debug&raquo;, kernel_kobj);<br />
	if (!debug_kobj)<br />
		return -EINVAL;</p>
<p>	retval = register_filesystem(&#038;debug_fs_type);<br />
	if (retval)<br />
		kobject_put(debug_kobj);<br />
	else<br />
		debugfs_registered = true;</p>
<p>	return retval;<br />
}</p>
<p>static void __exit debugfs_exit(void)<br />
{<br />
	debugfs_registered = false;</p>
<p>	simple_release_fs(&#038;debugfs_mount, &#038;debugfs_mount_count);<br />
	unregister_filesystem(&#038;debug_fs_type);<br />
	kobject_put(debug_kobj);<br />
}</p>
<p>core_initcall(debugfs_init);<br />
module_exit(debugfs_exit);<br />
MODULE_LICENSE(&raquo;GPL&raquo;);</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/inode-c-14/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>file.c</title>
		<link>http://lynyrd.ru/file-c-10</link>
		<comments>http://lynyrd.ru/file-c-10#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:45:55 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[debugfs]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1013</guid>
		<description><![CDATA[/*
 *  file.c &#8211; part of debugfs, a tiny little debug file system
 *
 *  Copyright (C) 2004 Greg Kroah-Hartman 
 *  Copyright (C) 2004 IBM Inc.
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License version
 *	2 as ]]></description>
			<content:encoded><![CDATA[<p>/*<br />
 *  file.c &#8211; part of debugfs, a tiny little debug file system<span id="more-1013"></span><br />
 *<br />
 *  Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com><br />
 *  Copyright (C) 2004 IBM Inc.<br />
 *<br />
 *	This program is free software; you can redistribute it and/or<br />
 *	modify it under the terms of the GNU General Public License version<br />
 *	2 as published by the Free Software Foundation.<br />
 *<br />
 *  debugfs is for people to use instead of /proc or /sys.<br />
 *  See Documentation/DocBook/filesystems for more details.<br />
 *<br />
 */</p>
<p>#include
<linux/module.h>
#include
<linux/fs.h>
#include
<linux/pagemap.h>
#include
<linux/namei.h>
#include
<linux/debugfs.h>
<p>static ssize_t default_read_file(struct file *file, char __user *buf,<br />
				 size_t count, loff_t *ppos)<br />
{<br />
	return 0;<br />
}</p>
<p>static ssize_t default_write_file(struct file *file, const char __user *buf,<br />
				   size_t count, loff_t *ppos)<br />
{<br />
	return count;<br />
}</p>
<p>static int default_open(struct inode *inode, struct file *file)<br />
{<br />
	if (inode->i_private)<br />
		file->private_data = inode->i_private;</p>
<p>	return 0;<br />
}</p>
<p>const struct file_operations debugfs_file_operations = {<br />
	.read =		default_read_file,<br />
	.write =	default_write_file,<br />
	.open =		default_open,<br />
};</p>
<p>static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd)<br />
{<br />
	nd_set_link(nd, dentry->d_inode->i_private);<br />
	return NULL;<br />
}</p>
<p>const struct inode_operations debugfs_link_operations = {<br />
	.readlink       = generic_readlink,<br />
	.follow_link    = debugfs_follow_link,<br />
};</p>
<p>static int debugfs_u8_set(void *data, u64 val)<br />
{<br />
	*(u8 *)data = val;<br />
	return 0;<br />
}<br />
static int debugfs_u8_get(void *data, u64 *val)<br />
{<br />
	*val = *(u8 *)data;<br />
	return 0;<br />
}<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, &laquo;%llu\n&raquo;);</p>
<p>/**<br />
 * debugfs_create_u8 &#8211; create a debugfs file that is used to read and write an unsigned 8-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 *<br />
 * This function creates a file in debugfs with the given name that<br />
 * contains the value of the variable @value.  If the @mode variable is so<br />
 * set, it can be read from, and written to.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_u8(const char *name, mode_t mode,<br />
				 struct dentry *parent, u8 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u8_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u8_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_u8);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_u8);</p>
<p>static int debugfs_u16_set(void *data, u64 val)<br />
{<br />
	*(u16 *)data = val;<br />
	return 0;<br />
}<br />
static int debugfs_u16_get(void *data, u64 *val)<br />
{<br />
	*val = *(u16 *)data;<br />
	return 0;<br />
}<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, &laquo;%llu\n&raquo;);</p>
<p>/**<br />
 * debugfs_create_u16 &#8211; create a debugfs file that is used to read and write an unsigned 16-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 *<br />
 * This function creates a file in debugfs with the given name that<br />
 * contains the value of the variable @value.  If the @mode variable is so<br />
 * set, it can be read from, and written to.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_u16(const char *name, mode_t mode,<br />
				  struct dentry *parent, u16 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u16_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u16_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_u16);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_u16);</p>
<p>static int debugfs_u32_set(void *data, u64 val)<br />
{<br />
	*(u32 *)data = val;<br />
	return 0;<br />
}<br />
static int debugfs_u32_get(void *data, u64 *val)<br />
{<br />
	*val = *(u32 *)data;<br />
	return 0;<br />
}<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, &laquo;%llu\n&raquo;);</p>
<p>/**<br />
 * debugfs_create_u32 &#8211; create a debugfs file that is used to read and write an unsigned 32-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 *<br />
 * This function creates a file in debugfs with the given name that<br />
 * contains the value of the variable @value.  If the @mode variable is so<br />
 * set, it can be read from, and written to.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_u32(const char *name, mode_t mode,<br />
				 struct dentry *parent, u32 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u32_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u32_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_u32);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_u32);</p>
<p>static int debugfs_u64_set(void *data, u64 val)<br />
{<br />
	*(u64 *)data = val;<br />
	return 0;<br />
}</p>
<p>static int debugfs_u64_get(void *data, u64 *val)<br />
{<br />
	*val = *(u64 *)data;<br />
	return 0;<br />
}<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, &laquo;%llu\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, &laquo;%llu\n&raquo;);</p>
<p>/**<br />
 * debugfs_create_u64 &#8211; create a debugfs file that is used to read and write an unsigned 64-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 *<br />
 * This function creates a file in debugfs with the given name that<br />
 * contains the value of the variable @value.  If the @mode variable is so<br />
 * set, it can be read from, and written to.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_u64(const char *name, mode_t mode,<br />
				 struct dentry *parent, u64 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u64_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_u64_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_u64);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_u64);</p>
<p>DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, &laquo;0x%02llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, &laquo;0x%02llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, &laquo;0x%02llx\n&raquo;);</p>
<p>DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, &laquo;0x%04llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, &laquo;0x%04llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, &laquo;0x%04llx\n&raquo;);</p>
<p>DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, &laquo;0x%08llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, &laquo;0x%08llx\n&raquo;);<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, &laquo;0x%08llx\n&raquo;);</p>
<p>/*<br />
 * debugfs_create_x{8,16,32} &#8211; create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value<br />
 *<br />
 * These functions are exactly the same as the above functions (but use a hex<br />
 * output for the decimal challenged). For details look at the above unsigned<br />
 * decimal functions.<br />
 */</p>
<p>/**<br />
 * debugfs_create_x8 &#8211; create a debugfs file that is used to read and write an unsigned 8-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 */<br />
struct dentry *debugfs_create_x8(const char *name, mode_t mode,<br />
				 struct dentry *parent, u8 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x8_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x8_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_x8);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_x8);</p>
<p>/**<br />
 * debugfs_create_x16 &#8211; create a debugfs file that is used to read and write an unsigned 16-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 */<br />
struct dentry *debugfs_create_x16(const char *name, mode_t mode,<br />
				 struct dentry *parent, u16 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x16_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x16_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_x16);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_x16);</p>
<p>/**<br />
 * debugfs_create_x32 &#8211; create a debugfs file that is used to read and write an unsigned 32-bit value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 */<br />
struct dentry *debugfs_create_x32(const char *name, mode_t mode,<br />
				 struct dentry *parent, u32 *value)<br />
{<br />
	/* if there are no write bits set, make read only */<br />
	if (!(mode &#038; S_IWUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x32_ro);<br />
	/* if there are no read bits set, make write only */<br />
	if (!(mode &#038; S_IRUGO))<br />
		return debugfs_create_file(name, mode, parent, value, &#038;fops_x32_wo);</p>
<p>	return debugfs_create_file(name, mode, parent, value, &#038;fops_x32);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_x32);</p>
<p>static int debugfs_size_t_set(void *data, u64 val)<br />
{<br />
	*(size_t *)data = val;<br />
	return 0;<br />
}<br />
static int debugfs_size_t_get(void *data, u64 *val)<br />
{<br />
	*val = *(size_t *)data;<br />
	return 0;<br />
}<br />
DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set,<br />
			&laquo;%llu\n&raquo;);	/* %llu and %zu are more or less the same */</p>
<p>/**<br />
 * debugfs_create_size_t &#8211; create a debugfs file that is used to read and write an size_t value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 */<br />
struct dentry *debugfs_create_size_t(const char *name, mode_t mode,<br />
				     struct dentry *parent, size_t *value)<br />
{<br />
	return debugfs_create_file(name, mode, parent, value, &#038;fops_size_t);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_size_t);</p>
<p>static ssize_t read_file_bool(struct file *file, char __user *user_buf,<br />
			      size_t count, loff_t *ppos)<br />
{<br />
	char buf[3];<br />
	u32 *val = file->private_data;</p>
<p>	if (*val)<br />
		buf[0] = &#8216;Y&#8217;;<br />
	else<br />
		buf[0] = &#8216;N&#8217;;<br />
	buf[1] = &#8216;\n&#8217;;<br />
	buf[2] = 0&#215;00;<br />
	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);<br />
}</p>
<p>static ssize_t write_file_bool(struct file *file, const char __user *user_buf,<br />
			       size_t count, loff_t *ppos)<br />
{<br />
	char buf[32];<br />
	int buf_size;<br />
	u32 *val = file->private_data;</p>
<p>	buf_size = min(count, (sizeof(buf)-1));<br />
	if (copy_from_user(buf, user_buf, buf_size))<br />
		return -EFAULT;</p>
<p>	switch (buf[0]) {<br />
	case &#8216;y&#8217;:<br />
	case &#8216;Y&#8217;:<br />
	case &#8216;1&#8242;:<br />
		*val = 1;<br />
		break;<br />
	case &#8216;n&#8217;:<br />
	case &#8216;N&#8217;:<br />
	case &#8216;0&#8242;:<br />
		*val = 0;<br />
		break;<br />
	}</p>
<p>	return count;<br />
}</p>
<p>static const struct file_operations fops_bool = {<br />
	.read =		read_file_bool,<br />
	.write =	write_file_bool,<br />
	.open =		default_open,<br />
};</p>
<p>/**<br />
 * debugfs_create_bool &#8211; create a debugfs file that is used to read and write a boolean value<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @value: a pointer to the variable that the file should read to and write<br />
 *         from.<br />
 *<br />
 * This function creates a file in debugfs with the given name that<br />
 * contains the value of the variable @value.  If the @mode variable is so<br />
 * set, it can be read from, and written to.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_bool(const char *name, mode_t mode,<br />
				   struct dentry *parent, u32 *value)<br />
{<br />
	return debugfs_create_file(name, mode, parent, value, &#038;fops_bool);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_bool);</p>
<p>static ssize_t read_file_blob(struct file *file, char __user *user_buf,<br />
			      size_t count, loff_t *ppos)<br />
{<br />
	struct debugfs_blob_wrapper *blob = file->private_data;<br />
	return simple_read_from_buffer(user_buf, count, ppos, blob->data,<br />
			blob->size);<br />
}</p>
<p>static const struct file_operations fops_blob = {<br />
	.read =		read_file_blob,<br />
	.open =		default_open,<br />
};</p>
<p>/**<br />
 * debugfs_create_blob &#8211; create a debugfs file that is used to read a binary blob<br />
 * @name: a pointer to a string containing the name of the file to create.<br />
 * @mode: the permission that the file should have<br />
 * @parent: a pointer to the parent dentry for this file.  This should be a<br />
 *          directory dentry if set.  If this parameter is %NULL, then the<br />
 *          file will be created in the root of the debugfs filesystem.<br />
 * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer<br />
 *        to the blob data and the size of the data.<br />
 *<br />
 * This function creates a file in debugfs with the given name that exports<br />
 * @blob->data as a binary blob. If the @mode variable is so set it can be<br />
 * read from. Writing is not supported.<br />
 *<br />
 * This function will return a pointer to a dentry if it succeeds.  This<br />
 * pointer must be passed to the debugfs_remove() function when the file is<br />
 * to be removed (no automatic cleanup happens if your module is unloaded,<br />
 * you are responsible here.)  If an error occurs, %NULL will be returned.<br />
 *<br />
 * If debugfs is not enabled in the kernel, the value -%ENODEV will be<br />
 * returned.  It is not wise to check for this value, but rather, check for<br />
 * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling<br />
 * code.<br />
 */<br />
struct dentry *debugfs_create_blob(const char *name, mode_t mode,<br />
				   struct dentry *parent,<br />
				   struct debugfs_blob_wrapper *blob)<br />
{<br />
	return debugfs_create_file(name, mode, parent, blob, &#038;fops_blob);<br />
}<br />
EXPORT_SYMBOL_GPL(debugfs_create_blob);</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/file-c-10/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
