34d024f843
The node maps that are set/unset by these votes are no longer relevant, thus we can remove the mount and umount votes. Since those are the last two remaining votes, we can also remove the entire vote infrastructure. The vote thread has been renamed to the downconvert thread, and the small amount of functionality related to managing it has been moved into fs/ocfs2/dlmglue.c. All references to votes have been removed or updated. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
304 lines
7.5 KiB
C
304 lines
7.5 KiB
C
/* -*- mode: c; c-basic-offset: 8; -*-
|
|
* vim: noexpandtab sw=8 ts=8 sts=0:
|
|
*
|
|
* heartbeat.c
|
|
*
|
|
* Register ourselves with the heartbaet service, keep our node maps
|
|
* up to date, and fire off recovery when needed.
|
|
*
|
|
* Copyright (C) 2002, 2004 Oracle. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 021110-1307, USA.
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/kmod.h>
|
|
|
|
#include <dlm/dlmapi.h>
|
|
|
|
#define MLOG_MASK_PREFIX ML_SUPER
|
|
#include <cluster/masklog.h>
|
|
|
|
#include "ocfs2.h"
|
|
|
|
#include "alloc.h"
|
|
#include "heartbeat.h"
|
|
#include "inode.h"
|
|
#include "journal.h"
|
|
|
|
#include "buffer_head_io.h"
|
|
|
|
static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map,
|
|
int bit);
|
|
static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map,
|
|
int bit);
|
|
static inline int __ocfs2_node_map_is_empty(struct ocfs2_node_map *map);
|
|
static void __ocfs2_node_map_dup(struct ocfs2_node_map *target,
|
|
struct ocfs2_node_map *from);
|
|
static void __ocfs2_node_map_set(struct ocfs2_node_map *target,
|
|
struct ocfs2_node_map *from);
|
|
|
|
void ocfs2_init_node_maps(struct ocfs2_super *osb)
|
|
{
|
|
spin_lock_init(&osb->node_map_lock);
|
|
ocfs2_node_map_init(&osb->recovery_map);
|
|
ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs);
|
|
}
|
|
|
|
static void ocfs2_do_node_down(int node_num,
|
|
struct ocfs2_super *osb)
|
|
{
|
|
BUG_ON(osb->node_num == node_num);
|
|
|
|
mlog(0, "ocfs2: node down event for %d\n", node_num);
|
|
|
|
if (!osb->dlm) {
|
|
/*
|
|
* No DLM means we're not even ready to participate yet.
|
|
* We check the slots after the DLM comes up, so we will
|
|
* notice the node death then. We can safely ignore it
|
|
* here.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
ocfs2_recovery_thread(osb, node_num);
|
|
}
|
|
|
|
/* Called from the dlm when it's about to evict a node. We may also
|
|
* get a heartbeat callback later. */
|
|
static void ocfs2_dlm_eviction_cb(int node_num,
|
|
void *data)
|
|
{
|
|
struct ocfs2_super *osb = (struct ocfs2_super *) data;
|
|
struct super_block *sb = osb->sb;
|
|
|
|
mlog(ML_NOTICE, "device (%u,%u): dlm has evicted node %d\n",
|
|
MAJOR(sb->s_dev), MINOR(sb->s_dev), node_num);
|
|
|
|
ocfs2_do_node_down(node_num, osb);
|
|
}
|
|
|
|
void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
|
|
{
|
|
/* Not exactly a heartbeat callback, but leads to essentially
|
|
* the same path so we set it up here. */
|
|
dlm_setup_eviction_cb(&osb->osb_eviction_cb,
|
|
ocfs2_dlm_eviction_cb,
|
|
osb);
|
|
}
|
|
|
|
void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
|
|
{
|
|
int ret;
|
|
char *argv[5], *envp[3];
|
|
|
|
if (ocfs2_mount_local(osb))
|
|
return;
|
|
|
|
if (!osb->uuid_str) {
|
|
/* This can happen if we don't get far enough in mount... */
|
|
mlog(0, "No UUID with which to stop heartbeat!\n\n");
|
|
return;
|
|
}
|
|
|
|
argv[0] = (char *)o2nm_get_hb_ctl_path();
|
|
argv[1] = "-K";
|
|
argv[2] = "-u";
|
|
argv[3] = osb->uuid_str;
|
|
argv[4] = NULL;
|
|
|
|
mlog(0, "Run: %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
|
|
|
|
/* minimal command environment taken from cpu_run_sbin_hotplug */
|
|
envp[0] = "HOME=/";
|
|
envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
|
|
envp[2] = NULL;
|
|
|
|
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
|
|
if (ret < 0)
|
|
mlog_errno(ret);
|
|
}
|
|
|
|
/* special case -1 for now
|
|
* TODO: should *really* make sure the calling func never passes -1!! */
|
|
void ocfs2_node_map_init(struct ocfs2_node_map *map)
|
|
{
|
|
map->num_nodes = OCFS2_NODE_MAP_MAX_NODES;
|
|
memset(map->map, 0, BITS_TO_LONGS(OCFS2_NODE_MAP_MAX_NODES) *
|
|
sizeof(unsigned long));
|
|
}
|
|
|
|
static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map,
|
|
int bit)
|
|
{
|
|
set_bit(bit, map->map);
|
|
}
|
|
|
|
void ocfs2_node_map_set_bit(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *map,
|
|
int bit)
|
|
{
|
|
if (bit==-1)
|
|
return;
|
|
BUG_ON(bit >= map->num_nodes);
|
|
spin_lock(&osb->node_map_lock);
|
|
__ocfs2_node_map_set_bit(map, bit);
|
|
spin_unlock(&osb->node_map_lock);
|
|
}
|
|
|
|
static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map,
|
|
int bit)
|
|
{
|
|
clear_bit(bit, map->map);
|
|
}
|
|
|
|
void ocfs2_node_map_clear_bit(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *map,
|
|
int bit)
|
|
{
|
|
if (bit==-1)
|
|
return;
|
|
BUG_ON(bit >= map->num_nodes);
|
|
spin_lock(&osb->node_map_lock);
|
|
__ocfs2_node_map_clear_bit(map, bit);
|
|
spin_unlock(&osb->node_map_lock);
|
|
}
|
|
|
|
int ocfs2_node_map_test_bit(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *map,
|
|
int bit)
|
|
{
|
|
int ret;
|
|
if (bit >= map->num_nodes) {
|
|
mlog(ML_ERROR, "bit=%d map->num_nodes=%d\n", bit, map->num_nodes);
|
|
BUG();
|
|
}
|
|
spin_lock(&osb->node_map_lock);
|
|
ret = test_bit(bit, map->map);
|
|
spin_unlock(&osb->node_map_lock);
|
|
return ret;
|
|
}
|
|
|
|
static inline int __ocfs2_node_map_is_empty(struct ocfs2_node_map *map)
|
|
{
|
|
int bit;
|
|
bit = find_next_bit(map->map, map->num_nodes, 0);
|
|
if (bit < map->num_nodes)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int ocfs2_node_map_is_empty(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *map)
|
|
{
|
|
int ret;
|
|
BUG_ON(map->num_nodes == 0);
|
|
spin_lock(&osb->node_map_lock);
|
|
ret = __ocfs2_node_map_is_empty(map);
|
|
spin_unlock(&osb->node_map_lock);
|
|
return ret;
|
|
}
|
|
|
|
static void __ocfs2_node_map_dup(struct ocfs2_node_map *target,
|
|
struct ocfs2_node_map *from)
|
|
{
|
|
BUG_ON(from->num_nodes == 0);
|
|
ocfs2_node_map_init(target);
|
|
__ocfs2_node_map_set(target, from);
|
|
}
|
|
|
|
/* returns 1 if bit is the only bit set in target, 0 otherwise */
|
|
int ocfs2_node_map_is_only(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *target,
|
|
int bit)
|
|
{
|
|
struct ocfs2_node_map temp;
|
|
int ret;
|
|
|
|
spin_lock(&osb->node_map_lock);
|
|
__ocfs2_node_map_dup(&temp, target);
|
|
__ocfs2_node_map_clear_bit(&temp, bit);
|
|
ret = __ocfs2_node_map_is_empty(&temp);
|
|
spin_unlock(&osb->node_map_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __ocfs2_node_map_set(struct ocfs2_node_map *target,
|
|
struct ocfs2_node_map *from)
|
|
{
|
|
int num_longs, i;
|
|
|
|
BUG_ON(target->num_nodes != from->num_nodes);
|
|
BUG_ON(target->num_nodes == 0);
|
|
|
|
num_longs = BITS_TO_LONGS(target->num_nodes);
|
|
for (i = 0; i < num_longs; i++)
|
|
target->map[i] = from->map[i];
|
|
}
|
|
|
|
/* Returns whether the recovery bit was actually set - it may not be
|
|
* if a node is still marked as needing recovery */
|
|
int ocfs2_recovery_map_set(struct ocfs2_super *osb,
|
|
int num)
|
|
{
|
|
int set = 0;
|
|
|
|
spin_lock(&osb->node_map_lock);
|
|
|
|
if (!test_bit(num, osb->recovery_map.map)) {
|
|
__ocfs2_node_map_set_bit(&osb->recovery_map, num);
|
|
set = 1;
|
|
}
|
|
|
|
spin_unlock(&osb->node_map_lock);
|
|
|
|
return set;
|
|
}
|
|
|
|
void ocfs2_recovery_map_clear(struct ocfs2_super *osb,
|
|
int num)
|
|
{
|
|
ocfs2_node_map_clear_bit(osb, &osb->recovery_map, num);
|
|
}
|
|
|
|
int ocfs2_node_map_iterate(struct ocfs2_super *osb,
|
|
struct ocfs2_node_map *map,
|
|
int idx)
|
|
{
|
|
int i = idx;
|
|
|
|
idx = O2NM_INVALID_NODE_NUM;
|
|
spin_lock(&osb->node_map_lock);
|
|
if ((i != O2NM_INVALID_NODE_NUM) &&
|
|
(i >= 0) &&
|
|
(i < map->num_nodes)) {
|
|
while(i < map->num_nodes) {
|
|
if (test_bit(i, map->map)) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
spin_unlock(&osb->node_map_lock);
|
|
return idx;
|
|
}
|