heartbeat.c 62.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * Copyright (C) 2004, 2005 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License 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/kernel.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/file.h>
#include <linux/kthread.h>
#include <linux/configfs.h>
#include <linux/random.h>
#include <linux/crc32.h>
#include <linux/time.h>
36
#include <linux/debugfs.h>
37
#include <linux/slab.h>
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#include "heartbeat.h"
#include "tcp.h"
#include "nodemanager.h"
#include "quorum.h"

#include "masklog.h"


/*
 * The first heartbeat pass had one global thread that would serialize all hb
 * callback calls.  This global serializing sem should only be removed once
 * we've made sure that all callees can deal with being called concurrently
 * from multiple hb region threads.
 */
static DECLARE_RWSEM(o2hb_callback_sem);

/*
 * multiple hb threads are watching multiple regions.  A node is live
 * whenever any of the threads sees activity from the node in its region.
 */
59
static DEFINE_SPINLOCK(o2hb_live_lock);
60
61
62
63
64
static struct list_head o2hb_live_slots[O2NM_MAX_NODES];
static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
static LIST_HEAD(o2hb_node_events);
static DECLARE_WAIT_QUEUE_HEAD(o2hb_steady_queue);

Sunil Mushran's avatar
   
Sunil Mushran committed
65
66
67
/*
 * In global heartbeat, we maintain a series of region bitmaps.
 * 	- o2hb_region_bitmap allows us to limit the region number to max region.
Sunil Mushran's avatar
   
Sunil Mushran committed
68
 * 	- o2hb_live_region_bitmap tracks live regions (seen steady iterations).
Sunil Mushran's avatar
   
Sunil Mushran committed
69
70
 * 	- o2hb_quorum_region_bitmap tracks live regions that have seen all nodes
 * 		heartbeat on it.
Sunil Mushran's avatar
   
Sunil Mushran committed
71
 * 	- o2hb_failed_region_bitmap tracks the regions that have seen io timeouts.
Sunil Mushran's avatar
   
Sunil Mushran committed
72
73
 */
static unsigned long o2hb_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
Sunil Mushran's avatar
   
Sunil Mushran committed
74
static unsigned long o2hb_live_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
Sunil Mushran's avatar
   
Sunil Mushran committed
75
static unsigned long o2hb_quorum_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
Sunil Mushran's avatar
   
Sunil Mushran committed
76
static unsigned long o2hb_failed_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
Sunil Mushran's avatar
   
Sunil Mushran committed
77

Sunil Mushran's avatar
   
Sunil Mushran committed
78
#define O2HB_DB_TYPE_LIVENODES		0
Sunil Mushran's avatar
   
Sunil Mushran committed
79
80
81
#define O2HB_DB_TYPE_LIVEREGIONS	1
#define O2HB_DB_TYPE_QUORUMREGIONS	2
#define O2HB_DB_TYPE_FAILEDREGIONS	3
Sunil Mushran's avatar
   
Sunil Mushran committed
82
83
#define O2HB_DB_TYPE_REGION_LIVENODES	4
#define O2HB_DB_TYPE_REGION_NUMBER	5
Sunil Mushran's avatar
   
Sunil Mushran committed
84
#define O2HB_DB_TYPE_REGION_ELAPSED_TIME	6
Sunil Mushran's avatar
   
Sunil Mushran committed
85
86
87
88
89
90
91
92
struct o2hb_debug_buf {
	int db_type;
	int db_size;
	int db_len;
	void *db_data;
};

static struct o2hb_debug_buf *o2hb_db_livenodes;
Sunil Mushran's avatar
   
Sunil Mushran committed
93
94
95
static struct o2hb_debug_buf *o2hb_db_liveregions;
static struct o2hb_debug_buf *o2hb_db_quorumregions;
static struct o2hb_debug_buf *o2hb_db_failedregions;
Sunil Mushran's avatar
   
Sunil Mushran committed
96

97
98
#define O2HB_DEBUG_DIR			"o2hb"
#define O2HB_DEBUG_LIVENODES		"livenodes"
Sunil Mushran's avatar
   
Sunil Mushran committed
99
100
101
#define O2HB_DEBUG_LIVEREGIONS		"live_regions"
#define O2HB_DEBUG_QUORUMREGIONS	"quorum_regions"
#define O2HB_DEBUG_FAILEDREGIONS	"failed_regions"
Sunil Mushran's avatar
   
Sunil Mushran committed
102
#define O2HB_DEBUG_REGION_NUMBER	"num"
Sunil Mushran's avatar
   
Sunil Mushran committed
103
#define O2HB_DEBUG_REGION_ELAPSED_TIME	"elapsed_time_in_ms"
Sunil Mushran's avatar
   
Sunil Mushran committed
104

105
106
static struct dentry *o2hb_debug_dir;
static struct dentry *o2hb_debug_livenodes;
Sunil Mushran's avatar
   
Sunil Mushran committed
107
108
109
static struct dentry *o2hb_debug_liveregions;
static struct dentry *o2hb_debug_quorumregions;
static struct dentry *o2hb_debug_failedregions;
110

111
112
113
114
115
116
117
118
119
120
static LIST_HEAD(o2hb_all_regions);

static struct o2hb_callback {
	struct list_head list;
} o2hb_callbacks[O2HB_NUM_CB];

static struct o2hb_callback *hbcall_from_type(enum o2hb_callback_type type);

#define O2HB_DEFAULT_BLOCK_BITS       9

Sunil Mushran's avatar
   
Sunil Mushran committed
121
122
123
124
125
126
127
128
129
130
131
enum o2hb_heartbeat_modes {
	O2HB_HEARTBEAT_LOCAL		= 0,
	O2HB_HEARTBEAT_GLOBAL,
	O2HB_HEARTBEAT_NUM_MODES,
};

char *o2hb_heartbeat_mode_desc[O2HB_HEARTBEAT_NUM_MODES] = {
		"local",	/* O2HB_HEARTBEAT_LOCAL */
		"global",	/* O2HB_HEARTBEAT_GLOBAL */
};

132
unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD;
Sunil Mushran's avatar
   
Sunil Mushran committed
133
unsigned int o2hb_heartbeat_mode = O2HB_HEARTBEAT_LOCAL;
134

135
/* Only sets a new threshold if there are no active regions.
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 *
 * No locking or otherwise interesting code is required for reading
 * o2hb_dead_threshold as it can't change once regions are active and
 * it's not interesting to anyone until then anyway. */
static void o2hb_dead_threshold_set(unsigned int threshold)
{
	if (threshold > O2HB_MIN_DEAD_THRESHOLD) {
		spin_lock(&o2hb_live_lock);
		if (list_empty(&o2hb_all_regions))
			o2hb_dead_threshold = threshold;
		spin_unlock(&o2hb_live_lock);
	}
}

Sunil Mushran's avatar
   
Sunil Mushran committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
static int o2hb_global_hearbeat_mode_set(unsigned int hb_mode)
{
	int ret = -1;

	if (hb_mode < O2HB_HEARTBEAT_NUM_MODES) {
		spin_lock(&o2hb_live_lock);
		if (list_empty(&o2hb_all_regions)) {
			o2hb_heartbeat_mode = hb_mode;
			ret = 0;
		}
		spin_unlock(&o2hb_live_lock);
	}

	return ret;
}

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
struct o2hb_node_event {
	struct list_head        hn_item;
	enum o2hb_callback_type hn_event_type;
	struct o2nm_node        *hn_node;
	int                     hn_node_num;
};

struct o2hb_disk_slot {
	struct o2hb_disk_heartbeat_block *ds_raw_block;
	u8			ds_node_num;
	u64			ds_last_time;
	u64			ds_last_generation;
	u16			ds_equal_samples;
	u16			ds_changed_samples;
	struct list_head	ds_live_item;
};

/* each thread owns a region.. when we're asked to tear down the region
 * we ask the thread to stop, who cleans up the region */
struct o2hb_region {
	struct config_item	hr_item;

	struct list_head	hr_all_item;
	unsigned		hr_unclean_stop:1;

	/* protected by the hr_callback_sem */
	struct task_struct 	*hr_task;

	unsigned int		hr_blocks;
	unsigned long long	hr_start_block;

	unsigned int		hr_block_bits;
	unsigned int		hr_block_bytes;

	unsigned int		hr_slots_per_page;
	unsigned int		hr_num_pages;

	struct page             **hr_slot_data;
	struct block_device	*hr_bdev;
	struct o2hb_disk_slot	*hr_slots;

Sunil Mushran's avatar
   
Sunil Mushran committed
207
208
	/* live node map of this region */
	unsigned long		hr_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
Sunil Mushran's avatar
   
Sunil Mushran committed
209
	unsigned int		hr_region_num;
Sunil Mushran's avatar
   
Sunil Mushran committed
210

Sunil Mushran's avatar
   
Sunil Mushran committed
211
212
213
	struct dentry		*hr_debug_dir;
	struct dentry		*hr_debug_livenodes;
	struct dentry		*hr_debug_regnum;
Sunil Mushran's avatar
   
Sunil Mushran committed
214
	struct dentry		*hr_debug_elapsed_time;
Sunil Mushran's avatar
   
Sunil Mushran committed
215
216
	struct o2hb_debug_buf	*hr_db_livenodes;
	struct o2hb_debug_buf	*hr_db_regnum;
Sunil Mushran's avatar
   
Sunil Mushran committed
217
	struct o2hb_debug_buf	*hr_db_elapsed_time;
Sunil Mushran's avatar
   
Sunil Mushran committed
218

219
220
221
222
223
224
225
226
227
228
229
230
231
	/* let the person setting up hb wait for it to return until it
	 * has reached a 'steady' state.  This will be fixed when we have
	 * a more complete api that doesn't lead to this sort of fragility. */
	atomic_t		hr_steady_iterations;

	char			hr_dev_name[BDEVNAME_SIZE];

	unsigned int		hr_timeout_ms;

	/* randomized as the region goes up and down so that a node
	 * recognizes a node going up and down in one iteration */
	u64			hr_generation;

David Howells's avatar
David Howells committed
232
	struct delayed_work	hr_write_timeout_work;
233
234
235
236
237
238
239
240
241
242
243
	unsigned long		hr_last_timeout_start;

	/* Used during o2hb_check_slot to hold a copy of the block
	 * being checked because we temporarily have to zero out the
	 * crc field. */
	struct o2hb_disk_heartbeat_block *hr_tmp_block;
};

struct o2hb_bio_wait_ctxt {
	atomic_t          wc_num_reqs;
	struct completion wc_io_complete;
244
	int               wc_error;
245
246
};

Sunil Mushran's avatar
   
Sunil Mushran committed
247
248
249
250
251
252
253
254
255
static int o2hb_pop_count(void *map, int count)
{
	int i = -1, pop = 0;

	while ((i = find_next_bit(map, count, i + 1)) < count)
		pop++;
	return pop;
}

David Howells's avatar
David Howells committed
256
static void o2hb_write_timeout(struct work_struct *work)
257
{
Sunil Mushran's avatar
   
Sunil Mushran committed
258
259
	int failed, quorum;
	unsigned long flags;
David Howells's avatar
David Howells committed
260
261
262
	struct o2hb_region *reg =
		container_of(work, struct o2hb_region,
			     hr_write_timeout_work.work);
263
264
265

	mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u "
	     "milliseconds\n", reg->hr_dev_name,
266
	     jiffies_to_msecs(jiffies - reg->hr_last_timeout_start));
Sunil Mushran's avatar
   
Sunil Mushran committed
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

	if (o2hb_global_heartbeat_active()) {
		spin_lock_irqsave(&o2hb_live_lock, flags);
		if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
			set_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
		failed = o2hb_pop_count(&o2hb_failed_region_bitmap,
					O2NM_MAX_REGIONS);
		quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap,
					O2NM_MAX_REGIONS);
		spin_unlock_irqrestore(&o2hb_live_lock, flags);

		mlog(ML_HEARTBEAT, "Number of regions %d, failed regions %d\n",
		     quorum, failed);

		/*
		 * Fence if the number of failed regions >= half the number
		 * of  quorum regions
		 */
		if ((failed << 1) < quorum)
			return;
	}

289
290
291
292
293
	o2quo_disk_timeout();
}

static void o2hb_arm_write_timeout(struct o2hb_region *reg)
{
294
295
	mlog(ML_HEARTBEAT, "Queue write timeout for %u ms\n",
	     O2HB_MAX_WRITE_TIMEOUT_MS);
296

Sunil Mushran's avatar
   
Sunil Mushran committed
297
298
299
300
301
	if (o2hb_global_heartbeat_active()) {
		spin_lock(&o2hb_live_lock);
		clear_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
		spin_unlock(&o2hb_live_lock);
	}
302
303
304
305
306
307
308
309
310
311
312
313
	cancel_delayed_work(&reg->hr_write_timeout_work);
	reg->hr_last_timeout_start = jiffies;
	schedule_delayed_work(&reg->hr_write_timeout_work,
			      msecs_to_jiffies(O2HB_MAX_WRITE_TIMEOUT_MS));
}

static void o2hb_disarm_write_timeout(struct o2hb_region *reg)
{
	cancel_delayed_work(&reg->hr_write_timeout_work);
	flush_scheduled_work();
}

314
static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc)
315
{
316
	atomic_set(&wc->wc_num_reqs, 1);
317
	init_completion(&wc->wc_io_complete);
318
	wc->wc_error = 0;
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
}

/* Used in error paths too */
static inline void o2hb_bio_wait_dec(struct o2hb_bio_wait_ctxt *wc,
				     unsigned int num)
{
	/* sadly atomic_sub_and_test() isn't available on all platforms.  The
	 * good news is that the fast path only completes one at a time */
	while(num--) {
		if (atomic_dec_and_test(&wc->wc_num_reqs)) {
			BUG_ON(num > 0);
			complete(&wc->wc_io_complete);
		}
	}
}

static void o2hb_wait_on_io(struct o2hb_region *reg,
			    struct o2hb_bio_wait_ctxt *wc)
{
	struct address_space *mapping = reg->hr_bdev->bd_inode->i_mapping;

	blk_run_address_space(mapping);
341
	o2hb_bio_wait_dec(wc, 1);
342
343
344
345

	wait_for_completion(&wc->wc_io_complete);
}

Al Viro's avatar
Al Viro committed
346
static void o2hb_bio_end_io(struct bio *bio,
347
348
349
350
			   int error)
{
	struct o2hb_bio_wait_ctxt *wc = bio->bi_private;

351
	if (error) {
352
		mlog(ML_ERROR, "IO Error %d\n", error);
353
354
		wc->wc_error = error;
	}
355
356

	o2hb_bio_wait_dec(wc, 1);
357
	bio_put(bio);
358
359
360
361
362
363
}

/* Setup a Bio to cover I/O against num_slots slots starting at
 * start_slot. */
static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
				      struct o2hb_bio_wait_ctxt *wc,
364
365
				      unsigned int *current_slot,
				      unsigned int max_slots)
366
{
367
	int len, current_page;
368
369
370
	unsigned int vec_len, vec_start;
	unsigned int bits = reg->hr_block_bits;
	unsigned int spp = reg->hr_slots_per_page;
371
	unsigned int cs = *current_slot;
372
373
374
375
376
377
378
	struct bio *bio;
	struct page *page;

	/* Testing has shown this allocation to take long enough under
	 * GFP_KERNEL that the local node can get fenced. It would be
	 * nicest if we could pre-allocate these bios and avoid this
	 * all together. */
379
	bio = bio_alloc(GFP_ATOMIC, 16);
380
381
382
383
384
385
386
	if (!bio) {
		mlog(ML_ERROR, "Could not alloc slots BIO!\n");
		bio = ERR_PTR(-ENOMEM);
		goto bail;
	}

	/* Must put everything in 512 byte sectors for the bio... */
387
	bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9);
388
389
390
391
	bio->bi_bdev = reg->hr_bdev;
	bio->bi_private = wc;
	bio->bi_end_io = o2hb_bio_end_io;

392
393
394
395
	vec_start = (cs << bits) % PAGE_CACHE_SIZE;
	while(cs < max_slots) {
		current_page = cs / spp;
		page = reg->hr_slot_data[current_page];
396

397
		vec_len = min(PAGE_CACHE_SIZE - vec_start,
398
			      (max_slots-cs) * (PAGE_CACHE_SIZE/spp) );
399
400

		mlog(ML_HB_BIO, "page %d, vec_len = %u, vec_start = %u\n",
401
		     current_page, vec_len, vec_start);
402
403

		len = bio_add_page(bio, page, vec_len, vec_start);
404
		if (len != vec_len) break;
405

406
		cs += vec_len / (PAGE_CACHE_SIZE/spp);
407
408
409
410
		vec_start = 0;
	}

bail:
411
	*current_slot = cs;
412
413
414
415
416
417
	return bio;
}

static int o2hb_read_slots(struct o2hb_region *reg,
			   unsigned int max_slots)
{
418
419
	unsigned int current_slot=0;
	int status;
420
421
422
	struct o2hb_bio_wait_ctxt wc;
	struct bio *bio;

423
	o2hb_bio_wait_init(&wc);
424

425
426
	while(current_slot < max_slots) {
		bio = o2hb_setup_one_bio(reg, &wc, &current_slot, max_slots);
427
428
429
430
431
432
		if (IS_ERR(bio)) {
			status = PTR_ERR(bio);
			mlog_errno(status);
			goto bail_and_wait;
		}

433
		atomic_inc(&wc.wc_num_reqs);
434
435
436
437
438
439
440
		submit_bio(READ, bio);
	}

	status = 0;

bail_and_wait:
	o2hb_wait_on_io(reg, &wc);
441
442
	if (wc.wc_error && !status)
		status = wc.wc_error;
443
444
445
446
447
448
449
450
451
452
453

	return status;
}

static int o2hb_issue_node_write(struct o2hb_region *reg,
				 struct o2hb_bio_wait_ctxt *write_wc)
{
	int status;
	unsigned int slot;
	struct bio *bio;

454
	o2hb_bio_wait_init(write_wc);
455
456
457

	slot = o2nm_this_node();

458
	bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1);
459
460
461
462
463
464
	if (IS_ERR(bio)) {
		status = PTR_ERR(bio);
		mlog_errno(status);
		goto bail;
	}

465
	atomic_inc(&write_wc->wc_num_reqs);
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
	submit_bio(WRITE, bio);

	status = 0;
bail:
	return status;
}

static u32 o2hb_compute_block_crc_le(struct o2hb_region *reg,
				     struct o2hb_disk_heartbeat_block *hb_block)
{
	__le32 old_cksum;
	u32 ret;

	/* We want to compute the block crc with a 0 value in the
	 * hb_cksum field. Save it off here and replace after the
	 * crc. */
	old_cksum = hb_block->hb_cksum;
	hb_block->hb_cksum = 0;

	ret = crc32_le(0, (unsigned char *) hb_block, reg->hr_block_bytes);

	hb_block->hb_cksum = old_cksum;

	return ret;
}

static void o2hb_dump_slot(struct o2hb_disk_heartbeat_block *hb_block)
{
494
495
496
497
498
	mlog(ML_ERROR, "Dump slot information: seq = 0x%llx, node = %u, "
	     "cksum = 0x%x, generation 0x%llx\n",
	     (long long)le64_to_cpu(hb_block->hb_seq),
	     hb_block->hb_node, le32_to_cpu(hb_block->hb_cksum),
	     (long long)le64_to_cpu(hb_block->hb_generation));
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
}

static int o2hb_verify_crc(struct o2hb_region *reg,
			   struct o2hb_disk_heartbeat_block *hb_block)
{
	u32 read, computed;

	read = le32_to_cpu(hb_block->hb_cksum);
	computed = o2hb_compute_block_crc_le(reg, hb_block);

	return read == computed;
}

/* We want to make sure that nobody is heartbeating on top of us --
 * this will help detect an invalid configuration. */
static int o2hb_check_last_timestamp(struct o2hb_region *reg)
{
	int node_num, ret;
	struct o2hb_disk_slot *slot;
	struct o2hb_disk_heartbeat_block *hb_block;

	node_num = o2nm_this_node();

	ret = 1;
	slot = &reg->hr_slots[node_num];
	/* Don't check on our 1st timestamp */
	if (slot->ds_last_time) {
		hb_block = slot->ds_raw_block;

		if (le64_to_cpu(hb_block->hb_seq) != slot->ds_last_time)
			ret = 0;
	}

	return ret;
}

static inline void o2hb_prepare_block(struct o2hb_region *reg,
				      u64 generation)
{
	int node_num;
	u64 cputime;
	struct o2hb_disk_slot *slot;
	struct o2hb_disk_heartbeat_block *hb_block;

	node_num = o2nm_this_node();
	slot = &reg->hr_slots[node_num];

	hb_block = (struct o2hb_disk_heartbeat_block *)slot->ds_raw_block;
	memset(hb_block, 0, reg->hr_block_bytes);
	/* TODO: time stuff */
	cputime = CURRENT_TIME.tv_sec;
	if (!cputime)
		cputime = 1;

	hb_block->hb_seq = cpu_to_le64(cputime);
	hb_block->hb_node = node_num;
	hb_block->hb_generation = cpu_to_le64(generation);
556
	hb_block->hb_dead_ms = cpu_to_le32(o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS);
557
558
559
560
561

	/* This step must always happen last! */
	hb_block->hb_cksum = cpu_to_le32(o2hb_compute_block_crc_le(reg,
								   hb_block));

562
	mlog(ML_HB_BIO, "our node generation = 0x%llx, cksum = 0x%x\n",
563
	     (long long)generation,
564
	     le32_to_cpu(hb_block->hb_cksum));
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
}

static void o2hb_fire_callbacks(struct o2hb_callback *hbcall,
				struct o2nm_node *node,
				int idx)
{
	struct list_head *iter;
	struct o2hb_callback_func *f;

	list_for_each(iter, &hbcall->list) {
		f = list_entry(iter, struct o2hb_callback_func, hc_item);
		mlog(ML_HEARTBEAT, "calling funcs %p\n", f);
		(f->hc_func)(node, idx, f->hc_data);
	}
}

/* Will run the list in order until we process the passed event */
static void o2hb_run_event_list(struct o2hb_node_event *queued_event)
{
	int empty;
	struct o2hb_callback *hbcall;
	struct o2hb_node_event *event;

	spin_lock(&o2hb_live_lock);
	empty = list_empty(&queued_event->hn_item);
	spin_unlock(&o2hb_live_lock);
	if (empty)
		return;

	/* Holding callback sem assures we don't alter the callback
	 * lists when doing this, and serializes ourselves with other
	 * processes wanting callbacks. */
	down_write(&o2hb_callback_sem);

	spin_lock(&o2hb_live_lock);
	while (!list_empty(&o2hb_node_events)
	       && !list_empty(&queued_event->hn_item)) {
		event = list_entry(o2hb_node_events.next,
				   struct o2hb_node_event,
				   hn_item);
		list_del_init(&event->hn_item);
		spin_unlock(&o2hb_live_lock);

		mlog(ML_HEARTBEAT, "Node %s event for %d\n",
		     event->hn_event_type == O2HB_NODE_UP_CB ? "UP" : "DOWN",
		     event->hn_node_num);

		hbcall = hbcall_from_type(event->hn_event_type);

		/* We should *never* have gotten on to the list with a
		 * bad type... This isn't something that we should try
		 * to recover from. */
		BUG_ON(IS_ERR(hbcall));

		o2hb_fire_callbacks(hbcall, event->hn_node, event->hn_node_num);

		spin_lock(&o2hb_live_lock);
	}
	spin_unlock(&o2hb_live_lock);

	up_write(&o2hb_callback_sem);
}

static void o2hb_queue_node_event(struct o2hb_node_event *event,
				  enum o2hb_callback_type type,
				  struct o2nm_node *node,
				  int node_num)
{
	assert_spin_locked(&o2hb_live_lock);

Sunil Mushran's avatar
   
Sunil Mushran committed
635
636
	BUG_ON((!node) && (type != O2HB_NODE_DOWN_CB));

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
	event->hn_event_type = type;
	event->hn_node = node;
	event->hn_node_num = node_num;

	mlog(ML_HEARTBEAT, "Queue node %s event for node %d\n",
	     type == O2HB_NODE_UP_CB ? "UP" : "DOWN", node_num);

	list_add_tail(&event->hn_item, &o2hb_node_events);
}

static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
{
	struct o2hb_node_event event =
		{ .hn_item = LIST_HEAD_INIT(event.hn_item), };
	struct o2nm_node *node;

	node = o2nm_get_node_by_num(slot->ds_node_num);
	if (!node)
		return;

	spin_lock(&o2hb_live_lock);
	if (!list_empty(&slot->ds_live_item)) {
		mlog(ML_HEARTBEAT, "Shutdown, node %d leaves region\n",
		     slot->ds_node_num);

		list_del_init(&slot->ds_live_item);

		if (list_empty(&o2hb_live_slots[slot->ds_node_num])) {
			clear_bit(slot->ds_node_num, o2hb_live_node_bitmap);

			o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB, node,
					      slot->ds_node_num);
		}
	}
	spin_unlock(&o2hb_live_lock);

	o2hb_run_event_list(&event);

	o2nm_node_put(node);
}

Sunil Mushran's avatar
   
Sunil Mushran committed
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
static void o2hb_set_quorum_device(struct o2hb_region *reg,
				   struct o2hb_disk_slot *slot)
{
	assert_spin_locked(&o2hb_live_lock);

	if (!o2hb_global_heartbeat_active())
		return;

	if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
		return;

	/*
	 * A region can be added to the quorum only when it sees all
	 * live nodes heartbeat on it. In other words, the region has been
	 * added to all nodes.
	 */
	if (memcmp(reg->hr_live_node_bitmap, o2hb_live_node_bitmap,
		   sizeof(o2hb_live_node_bitmap)))
		return;

	if (slot->ds_changed_samples < O2HB_LIVE_THRESHOLD)
		return;

	printk(KERN_NOTICE "o2hb: Region %s is now a quorum device\n",
	       config_item_name(&reg->hr_item));

	set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
}

707
708
709
710
711
712
713
714
715
static int o2hb_check_slot(struct o2hb_region *reg,
			   struct o2hb_disk_slot *slot)
{
	int changed = 0, gen_changed = 0;
	struct o2hb_node_event event =
		{ .hn_item = LIST_HEAD_INIT(event.hn_item), };
	struct o2nm_node *node;
	struct o2hb_disk_heartbeat_block *hb_block = reg->hr_tmp_block;
	u64 cputime;
716
717
	unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS;
	unsigned int slot_dead_ms;
Sunil Mushran's avatar
   
Sunil Mushran committed
718
	int tmp;
719
720
721

	memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes);

Sunil Mushran's avatar
   
Sunil Mushran committed
722
723
724
725
	/*
	 * If a node is no longer configured but is still in the livemap, we
	 * may need to clear that bit from the livemap.
	 */
726
	node = o2nm_get_node_by_num(slot->ds_node_num);
Sunil Mushran's avatar
   
Sunil Mushran committed
727
728
729
730
731
732
733
	if (!node) {
		spin_lock(&o2hb_live_lock);
		tmp = test_bit(slot->ds_node_num, o2hb_live_node_bitmap);
		spin_unlock(&o2hb_live_lock);
		if (!tmp)
			return 0;
	}
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773

	if (!o2hb_verify_crc(reg, hb_block)) {
		/* all paths from here will drop o2hb_live_lock for
		 * us. */
		spin_lock(&o2hb_live_lock);

		/* Don't print an error on the console in this case -
		 * a freshly formatted heartbeat area will not have a
		 * crc set on it. */
		if (list_empty(&slot->ds_live_item))
			goto out;

		/* The node is live but pushed out a bad crc. We
		 * consider it a transient miss but don't populate any
		 * other values as they may be junk. */
		mlog(ML_ERROR, "Node %d has written a bad crc to %s\n",
		     slot->ds_node_num, reg->hr_dev_name);
		o2hb_dump_slot(hb_block);

		slot->ds_equal_samples++;
		goto fire_callbacks;
	}

	/* we don't care if these wrap.. the state transitions below
	 * clear at the right places */
	cputime = le64_to_cpu(hb_block->hb_seq);
	if (slot->ds_last_time != cputime)
		slot->ds_changed_samples++;
	else
		slot->ds_equal_samples++;
	slot->ds_last_time = cputime;

	/* The node changed heartbeat generations. We assume this to
	 * mean it dropped off but came back before we timed out. We
	 * want to consider it down for the time being but don't want
	 * to lose any changed_samples state we might build up to
	 * considering it live again. */
	if (slot->ds_last_generation != le64_to_cpu(hb_block->hb_generation)) {
		gen_changed = 1;
		slot->ds_equal_samples = 0;
774
775
776
777
		mlog(ML_HEARTBEAT, "Node %d changed generation (0x%llx "
		     "to 0x%llx)\n", slot->ds_node_num,
		     (long long)slot->ds_last_generation,
		     (long long)le64_to_cpu(hb_block->hb_generation));
778
779
780
781
	}

	slot->ds_last_generation = le64_to_cpu(hb_block->hb_generation);

782
783
784
785
	mlog(ML_HEARTBEAT, "Slot %d gen 0x%llx cksum 0x%x "
	     "seq %llu last %llu changed %u equal %u\n",
	     slot->ds_node_num, (long long)slot->ds_last_generation,
	     le32_to_cpu(hb_block->hb_cksum),
786
	     (unsigned long long)le64_to_cpu(hb_block->hb_seq),
787
	     (unsigned long long)slot->ds_last_time, slot->ds_changed_samples,
788
789
790
791
792
793
794
795
796
	     slot->ds_equal_samples);

	spin_lock(&o2hb_live_lock);

fire_callbacks:
	/* dead nodes only come to life after some number of
	 * changes at any time during their dead time */
	if (list_empty(&slot->ds_live_item) &&
	    slot->ds_changed_samples >= O2HB_LIVE_THRESHOLD) {
797
798
		mlog(ML_HEARTBEAT, "Node %d (id 0x%llx) joined my region\n",
		     slot->ds_node_num, (long long)slot->ds_last_generation);
799

Sunil Mushran's avatar
   
Sunil Mushran committed
800
801
		set_bit(slot->ds_node_num, reg->hr_live_node_bitmap);

802
803
		/* first on the list generates a callback */
		if (list_empty(&o2hb_live_slots[slot->ds_node_num])) {
Sunil Mushran's avatar
   
Sunil Mushran committed
804
805
			mlog(ML_HEARTBEAT, "o2hb: Add node %d to live nodes "
			     "bitmap\n", slot->ds_node_num);
806
807
808
809
810
811
812
813
814
815
816
817
			set_bit(slot->ds_node_num, o2hb_live_node_bitmap);

			o2hb_queue_node_event(&event, O2HB_NODE_UP_CB, node,
					      slot->ds_node_num);

			changed = 1;
		}

		list_add_tail(&slot->ds_live_item,
			      &o2hb_live_slots[slot->ds_node_num]);

		slot->ds_equal_samples = 0;
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834

		/* We want to be sure that all nodes agree on the
		 * number of milliseconds before a node will be
		 * considered dead. The self-fencing timeout is
		 * computed from this value, and a discrepancy might
		 * result in heartbeat calling a node dead when it
		 * hasn't self-fenced yet. */
		slot_dead_ms = le32_to_cpu(hb_block->hb_dead_ms);
		if (slot_dead_ms && slot_dead_ms != dead_ms) {
			/* TODO: Perhaps we can fail the region here. */
			mlog(ML_ERROR, "Node %d on device %s has a dead count "
			     "of %u ms, but our count is %u ms.\n"
			     "Please double check your configuration values "
			     "for 'O2CB_HEARTBEAT_THRESHOLD'\n",
			     slot->ds_node_num, reg->hr_dev_name, slot_dead_ms,
			     dead_ms);
		}
835
836
837
838
839
840
841
842
843
844
845
846
847
848
		goto out;
	}

	/* if the list is dead, we're done.. */
	if (list_empty(&slot->ds_live_item))
		goto out;

	/* live nodes only go dead after enough consequtive missed
	 * samples..  reset the missed counter whenever we see
	 * activity */
	if (slot->ds_equal_samples >= o2hb_dead_threshold || gen_changed) {
		mlog(ML_HEARTBEAT, "Node %d left my region\n",
		     slot->ds_node_num);

Sunil Mushran's avatar
   
Sunil Mushran committed
849
850
		clear_bit(slot->ds_node_num, reg->hr_live_node_bitmap);

851
852
853
		/* last off the live_slot generates a callback */
		list_del_init(&slot->ds_live_item);
		if (list_empty(&o2hb_live_slots[slot->ds_node_num])) {
Sunil Mushran's avatar
   
Sunil Mushran committed
854
855
			mlog(ML_HEARTBEAT, "o2hb: Remove node %d from live "
			     "nodes bitmap\n", slot->ds_node_num);
856
857
			clear_bit(slot->ds_node_num, o2hb_live_node_bitmap);

Sunil Mushran's avatar
   
Sunil Mushran committed
858
859
860
			/* node can be null */
			o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB,
					      node, slot->ds_node_num);
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875

			changed = 1;
		}

		/* We don't clear this because the node is still
		 * actually writing new blocks. */
		if (!gen_changed)
			slot->ds_changed_samples = 0;
		goto out;
	}
	if (slot->ds_changed_samples) {
		slot->ds_changed_samples = 0;
		slot->ds_equal_samples = 0;
	}
out:
Sunil Mushran's avatar
   
Sunil Mushran committed
876
877
	o2hb_set_quorum_device(reg, slot);

878
879
880
881
	spin_unlock(&o2hb_live_lock);

	o2hb_run_event_list(&event);

Sunil Mushran's avatar
   
Sunil Mushran committed
882
883
	if (node)
		o2nm_node_put(node);
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
	return changed;
}

/* This could be faster if we just implmented a find_last_bit, but I
 * don't think the circumstances warrant it. */
static int o2hb_highest_node(unsigned long *nodes,
			     int numbits)
{
	int highest, node;

	highest = numbits;
	node = -1;
	while ((node = find_next_bit(nodes, numbits, node + 1)) != -1) {
		if (node >= numbits)
			break;

		highest = node;
	}

	return highest;
}

906
static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
907
908
909
{
	int i, ret, highest_node, change = 0;
	unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)];
Sunil Mushran's avatar
   
Sunil Mushran committed
910
	unsigned long live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
911
912
	struct o2hb_bio_wait_ctxt write_wc;

913
914
915
916
917
918
	ret = o2nm_configured_node_map(configured_nodes,
				       sizeof(configured_nodes));
	if (ret) {
		mlog_errno(ret);
		return ret;
	}
919

Sunil Mushran's avatar
   
Sunil Mushran committed
920
921
922
923
924
925
926
927
928
929
930
	/*
	 * If a node is not configured but is in the livemap, we still need
	 * to read the slot so as to be able to remove it from the livemap.
	 */
	o2hb_fill_node_map(live_node_bitmap, sizeof(live_node_bitmap));
	i = -1;
	while ((i = find_next_bit(live_node_bitmap,
				  O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {
		set_bit(i, configured_nodes);
	}

931
932
933
	highest_node = o2hb_highest_node(configured_nodes, O2NM_MAX_NODES);
	if (highest_node >= O2NM_MAX_NODES) {
		mlog(ML_NOTICE, "ocfs2_heartbeat: no configured nodes found!\n");
934
		return -EINVAL;
935
936
937
938
939
940
941
942
943
	}

	/* No sense in reading the slots of nodes that don't exist
	 * yet. Of course, if the node definitions have holes in them
	 * then we're reading an empty slot anyway... Consider this
	 * best-effort. */
	ret = o2hb_read_slots(reg, highest_node + 1);
	if (ret < 0) {
		mlog_errno(ret);
944
		return ret;
945
946
947
948
949
950
951
952
953
954
955
956
957
958
	}

	/* With an up to date view of the slots, we can check that no
	 * other node has been improperly configured to heartbeat in
	 * our slot. */
	if (!o2hb_check_last_timestamp(reg))
		mlog(ML_ERROR, "Device \"%s\": another node is heartbeating "
		     "in our slot!\n", reg->hr_dev_name);

	/* fill in the proper info for our next heartbeat */
	o2hb_prepare_block(reg, reg->hr_generation);

	/* And fire off the write. Note that we don't wait on this I/O
	 * until later. */
959
	ret = o2hb_issue_node_write(reg, &write_wc);
960
961
	if (ret < 0) {
		mlog_errno(ret);
962
		return ret;
963
964
965
966
967
968
969
970
971
972
973
974
975
976
	}

	i = -1;
	while((i = find_next_bit(configured_nodes, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {

		change |= o2hb_check_slot(reg, &reg->hr_slots[i]);
	}

	/*
	 * We have to be sure we've advertised ourselves on disk
	 * before we can go to steady state.  This ensures that
	 * people we find in our steady state have seen us.
	 */
	o2hb_wait_on_io(reg, &write_wc);
977
978
979
980
981
982
983
984
985
	if (write_wc.wc_error) {
		/* Do not re-arm the write timeout on I/O error - we
		 * can't be sure that the new block ever made it to
		 * disk */
		mlog(ML_ERROR, "Write error %d on device \"%s\"\n",
		     write_wc.wc_error, reg->hr_dev_name);
		return write_wc.wc_error;
	}

986
987
988
989
990
991
992
	o2hb_arm_write_timeout(reg);

	/* let the person who launched us know when things are steady */
	if (!change && (atomic_read(&reg->hr_steady_iterations) != 0)) {
		if (atomic_dec_and_test(&reg->hr_steady_iterations))
			wake_up(&o2hb_steady_queue);
	}
993
994

	return 0;
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
}

/* Subtract b from a, storing the result in a. a *must* have a larger
 * value than b. */
static void o2hb_tv_subtract(struct timeval *a,
			     struct timeval *b)
{
	/* just return 0 when a is after b */
	if (a->tv_sec < b->tv_sec ||
	    (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec)) {
		a->tv_sec = 0;
		a->tv_usec = 0;
		return;
	}

	a->tv_sec -= b->tv_sec;
	a->tv_usec -= b->tv_usec;
	while ( a->tv_usec < 0 ) {
		a->tv_sec--;
		a->tv_usec += 1000000;
	}
}

static unsigned int o2hb_elapsed_msecs(struct timeval *start,
				       struct timeval *end)
{
	struct timeval res = *end;

	o2hb_tv_subtract(&res, start);

	return res.tv_sec * 1000 + res.tv_usec / 1000;
}

/*
 * we ride the region ref that the region dir holds.  before the region
 * dir is removed and drops it ref it will wait to tear down this
 * thread.
 */
static int o2hb_thread(void *data)
{
	int i, ret;
	struct o2hb_region *reg = data;
	struct o2hb_bio_wait_ctxt write_wc;
	struct timeval before_hb, after_hb;
	unsigned int elapsed_msec;

	mlog(ML_HEARTBEAT|ML_KTHREAD, "hb thread running\n");

	set_user_nice(current, -20);

	while (!kthread_should_stop() && !reg->hr_unclean_stop) {
		/* We track the time spent inside
1047
		 * o2hb_do_disk_heartbeat so that we avoid more than
1048
1049
1050
1051
1052
		 * hr_timeout_ms between disk writes. On busy systems
		 * this should result in a heartbeat which is less
		 * likely to time itself out. */
		do_gettimeofday(&before_hb);

1053
1054
1055
1056
		i = 0;
		do {
			ret = o2hb_do_disk_heartbeat(reg);
		} while (ret && ++i < 2);
1057
1058
1059
1060

		do_gettimeofday(&after_hb);
		elapsed_msec = o2hb_elapsed_msecs(&before_hb, &after_hb);

1061
1062
		mlog(ML_HEARTBEAT,
		     "start = %lu.%lu, end = %lu.%lu, msec = %u\n",
1063
1064
1065
		     before_hb.tv_sec, (unsigned long) before_hb.tv_usec,
		     after_hb.tv_sec, (unsigned long) after_hb.tv_usec,
		     elapsed_msec);
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086

		if (elapsed_msec < reg->hr_timeout_ms) {
			/* the kthread api has blocked signals for us so no
			 * need to record the return value. */
			msleep_interruptible(reg->hr_timeout_ms - elapsed_msec);
		}
	}

	o2hb_disarm_write_timeout(reg);

	/* unclean stop is only used in very bad situation */
	for(i = 0; !reg->hr_unclean_stop && i < reg->hr_blocks; i++)
		o2hb_shutdown_slot(&reg->hr_slots[i]);

	/* Explicit down notification - avoid forcing the other nodes
	 * to timeout on this region when we could just as easily
	 * write a clear generation - thus indicating to them that
	 * this node has left this region.
	 *
	 * XXX: Should we skip this on unclean_stop? */
	o2hb_prepare_block(reg, 0);
1087
	ret = o2hb_issue_node_write(reg, &write_wc);
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
	if (ret == 0) {
		o2hb_wait_on_io(reg, &write_wc);
	} else {
		mlog_errno(ret);
	}

	mlog(ML_HEARTBEAT|ML_KTHREAD, "hb thread exiting\n");

	return 0;
}

1099
1100
1101
#ifdef CONFIG_DEBUG_FS
static int o2hb_debug_open(struct inode *inode, struct file *file)
{
Sunil Mushran's avatar
   
Sunil Mushran committed
1102
	struct o2hb_debug_buf *db = inode->i_private;
Sunil Mushran's avatar
   
Sunil Mushran committed
1103
	struct o2hb_region *reg;
1104
1105
1106
1107
1108
	unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
	char *buf = NULL;
	int i = -1;
	int out = 0;

Sunil Mushran's avatar
   
Sunil Mushran committed
1109
1110
1111
	/* max_nodes should be the largest bitmap we pass here */
	BUG_ON(sizeof(map) < db->db_size);

1112
1113
1114
1115
	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!buf)
		goto bail;

Sunil Mushran's avatar
   
Sunil Mushran committed
1116
1117
	switch (db->db_type) {
	case O2HB_DB_TYPE_LIVENODES:
Sunil Mushran's avatar
   
Sunil Mushran committed
1118
1119
1120
	case O2HB_DB_TYPE_LIVEREGIONS:
	case O2HB_DB_TYPE_QUORUMREGIONS:
	case O2HB_DB_TYPE_FAILEDREGIONS:
Sunil Mushran's avatar
   
Sunil Mushran committed
1121
1122
1123
1124
		spin_lock(&o2hb_live_lock);
		memcpy(map, db->db_data, db->db_size);
		spin_unlock(&o2hb_live_lock);
		break;
1125

Sunil Mushran's avatar
   
Sunil Mushran committed
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
	case O2HB_DB_TYPE_REGION_LIVENODES:
		spin_lock(&o2hb_live_lock);
		reg = (struct o2hb_region *)db->db_data;
		memcpy(map, reg->hr_live_node_bitmap, db->db_size);
		spin_unlock(&o2hb_live_lock);
		break;

	case O2HB_DB_TYPE_REGION_NUMBER:
		reg = (struct o2hb_region *)db->db_data;
		out += snprintf(buf + out, PAGE_SIZE - out, "%d\n",
				reg->hr_region_num);
		goto done;

Sunil Mushran's avatar
   
Sunil Mushran committed
1139
1140
1141
1142
1143
1144
1145
	case O2HB_DB_TYPE_REGION_ELAPSED_TIME:
		reg = (struct o2hb_region *)db->db_data;
		out += snprintf(buf + out, PAGE_SIZE - out, "%u\n",
				jiffies_to_msecs(jiffies -
						 reg->hr_last_timeout_start));
		goto done;

Sunil Mushran's avatar
   
Sunil Mushran committed
1146
1147
1148
1149
1150
	default:
		goto done;
	}

	while ((i = find_next_bit(map, db->db_len, i + 1)) < db->db_len)
1151
1152
1153
		out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i);
	out += snprintf(buf + out, PAGE_SIZE - out, "\n");

Sunil Mushran's avatar
   
Sunil Mushran committed
1154
done:
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
	i_size_write(inode, out);

	file->private_data = buf;

	return 0;
bail:
	return -ENOMEM;
}

static int o2hb_debug_release(struct inode *inode, struct file *file)
{
	kfree(file->private_data);
	return 0;
}

static ssize_t o2hb_debug_read(struct file *file, char __user *buf,
				 size_t nbytes, loff_t *ppos)
{
	return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
				       i_size_read(file->f_mapping->host));
}
#else
static int o2hb_debug_open(struct inode *inode, struct file *file)
{
	return 0;
}
static int o2hb_debug_release(struct inode *inode, struct file *file)
{
	return 0;
}
static ssize_t o2hb_debug_read(struct file *file, char __user *buf,
			       size_t nbytes, loff_t *ppos)
{
	return 0;
}
#endif  /* CONFIG_DEBUG_FS */

1192
static const struct file_operations o2hb_debug_fops = {
1193
1194
1195
1196
1197
1198
1199
1200
	.open =		o2hb_debug_open,
	.release =	o2hb_debug_release,
	.read =		o2hb_debug_read,
	.llseek =	generic_file_llseek,
};

void o2hb_exit(void)
{
Sunil Mushran's avatar
   
Sunil Mushran committed
1201
	kfree(o2hb_db_livenodes);
Sunil Mushran's avatar
   
Sunil Mushran committed
1202
1203
1204
1205
1206
1207
	kfree(o2hb_db_liveregions);
	kfree(o2hb_db_quorumregions);
	kfree(o2hb_db_failedregions);
	debugfs_remove(o2hb_debug_failedregions);
	debugfs_remove(o2hb_debug_quorumregions);
	debugfs_remove(o2hb_debug_liveregions);
Sunil Mushran's avatar
   
Sunil Mushran committed
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
	debugfs_remove(o2hb_debug_livenodes);
	debugfs_remove(o2hb_debug_dir);
}

static struct dentry *o2hb_debug_create(const char *name, struct dentry *dir,
					struct o2hb_debug_buf **db, int db_len,
					int type, int size, int len, void *data)
{
	*db = kmalloc(db_len, GFP_KERNEL);
	if (!*db)
		return NULL;

	(*db)->db_type = type;
	(*db)->db_size = size;
	(*db)->db_len = len;
	(*db)->db_data = data;

	return debugfs_create_file(name, S_IFREG|S_IRUSR, dir, *db,
				   &o2hb_debug_fops);
}

static int o2hb_debug_init(void)
{
	int ret = -ENOMEM;

	o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL);
	if (!o2hb_debug_dir) {
		mlog_errno(ret);
		goto bail;
	}

	o2hb_debug_livenodes = o2hb_debug_create(O2HB_DEBUG_LIVENODES,
						 o2hb_debug_dir,
						 &o2hb_db_livenodes,
						 sizeof(*o2hb_db_livenodes),
						 O2HB_DB_TYPE_LIVENODES,
						 sizeof(o2hb_live_node_bitmap),
						 O2NM_MAX_NODES,
						 o2hb_live_node_bitmap);
	if (!o2hb_debug_livenodes) {
		mlog_errno(ret);
		goto bail;
	}
Sunil Mushran's avatar
   
Sunil Mushran committed
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292

	o2hb_debug_liveregions = o2hb_debug_create(O2HB_DEBUG_LIVEREGIONS,
						   o2hb_debug_dir,
						   &o2hb_db_liveregions,
						   sizeof(*o2hb_db_liveregions),
						   O2HB_DB_TYPE_LIVEREGIONS,
						   sizeof(o2hb_live_region_bitmap),
						   O2NM_MAX_REGIONS,
						   o2hb_live_region_bitmap);
	if (!o2hb_debug_liveregions) {
		mlog_errno(ret);
		goto bail;
	}

	o2hb_debug_quorumregions =
			o2hb_debug_create(O2HB_DEBUG_QUORUMREGIONS,
					  o2hb_debug_dir,
					  &o2hb_db_quorumregions,
					  sizeof(*o2hb_db_quorumregions),
					  O2HB_DB_TYPE_QUORUMREGIONS,
					  sizeof(o2hb_quorum_region_bitmap),
					  O2NM_MAX_REGIONS,
					  o2hb_quorum_region_bitmap);
	if (!o2hb_debug_quorumregions) {
		mlog_errno(ret);
		goto bail;
	}

	o2hb_debug_failedregions =
			o2hb_debug_create(O2HB_DEBUG_FAILEDREGIONS,
					  o2hb_debug_dir,
					  &o2hb_db_failedregions,
					  sizeof(*o2hb_db_failedregions),
					  O2HB_DB_TYPE_FAILEDREGIONS,
					  sizeof(o2hb_failed_region_bitmap),
					  O2NM_MAX_REGIONS,
					  o2hb_failed_region_bitmap);
	if (!o2hb_debug_failedregions) {
		mlog_errno(ret);
		goto bail;
	}

Sunil Mushran's avatar
   
Sunil Mushran committed
1293
1294
1295
1296
1297
1298
	ret = 0;
bail:
	if (ret)
		o2hb_exit();

	return ret;
1299
1300
1301
}

int o2hb_init(void)
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
{
	int i;

	for (i = 0; i < ARRAY_SIZE(o2hb_callbacks); i++)
		INIT_LIST_HEAD(&o2hb_callbacks[i].list);

	for (i = 0; i < ARRAY_SIZE(o2hb_live_slots); i++)
		INIT_LIST_HEAD(&o2hb_live_slots[i]);

	INIT_LIST_HEAD(&o2hb_node_events);

	memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap));
Sunil Mushran's avatar
   
Sunil Mushran committed
1314
	memset(o2hb_region_bitmap, 0, sizeof(o2hb_region_bitmap));
Sunil Mushran's avatar
   
Sunil Mushran committed
1315
	memset(o2hb_live_region_bitmap, 0, sizeof(o2hb_live_region_bitmap));
Sunil Mushran's avatar
   
Sunil Mushran committed
1316
	memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap));
Sunil Mushran's avatar
   
Sunil Mushran committed
1317
	memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap));
1318

Sunil Mushran's avatar
   
Sunil Mushran committed
1319
	return o2hb_debug_init();
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
}

/* if we're already in a callback then we're already serialized by the sem */
static void o2hb_fill_node_map_from_callback(unsigned long *map,
					     unsigned bytes)
{
	BUG_ON(bytes < (BITS_TO_LONGS(O2NM_MAX_NODES) * sizeof(unsigned long)));

	memcpy(map, &o2hb_live_node_bitmap, bytes);
}

/*
 * get a map of all nodes that are heartbeating in any regions
 */
void o2hb_fill_node_map(unsigned long *map, unsigned bytes)
{
	/* callers want to serialize this map and callbacks so that they
	 * can trust that they don't miss nodes coming to the party */
	down_read(&o2hb_callback_sem);
	spin_lock(&o2hb_live_lock);
	o2hb_fill_node_map_from_callback(map, bytes);
	spin_unlock(&o2hb_live_lock);
	up_read(&o2hb_callback_sem);
}
EXPORT_SYMBOL_GPL(o2hb_fill_node_map);

/*
 * heartbeat configfs bits.  The heartbeat set is a default set under
 * the cluster set in nodemanager.c.
 */

static struct o2hb_region *to_o2hb_region(struct config_item *item)
{
	return item ? container_of(item, struct o2hb_region, hr_item) : NULL;
}

/* drop_item only drops its ref after killing the thread, nothing should
 * be using the region anymore.  this has to clean up any state that
 * attributes might have built up. */
static void o2hb_region_release(struct config_item *item)
{
	int i;
	struct page *page;
	struct o2hb_region *reg = to_o2hb_region(item);

	if (reg->hr_tmp_block)
		kfree(reg->hr_tmp_block);

	if (reg->hr_slot_data) {
		for (i = 0; i < reg->hr_num_pages; i++) {
			page = reg->hr_slot_data[i];
			if (page)
				__free_page(page);
		}
		kfree(reg->hr_slot_data);
	}

	if (reg->hr_bdev)
Al Viro's avatar
Al Viro committed
1378
		blkdev_put(reg->hr_bdev, FMODE_READ|FMODE_WRITE);
1379
1380
1381
1382

	if (reg->hr_slots)
		kfree(reg->hr_slots);

Sunil Mushran's avatar
   
Sunil Mushran committed
1383
1384
1385
1386
	kfree(reg->hr_db_regnum);
	kfree(reg->hr_db_livenodes);
	debugfs_remove(reg->hr_debug_livenodes);
	debugfs_remove(reg->hr_debug_regnum);
Sunil Mushran's avatar
   
Sunil Mushran committed
1387
	debugfs_remove(reg->hr_debug_elapsed_time);
Sunil Mushran's avatar
   
Sunil Mushran committed
1388
1389
	debugfs_remove(reg->hr_debug_dir);

1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
	spin_lock(&o2hb_live_lock);
	list_del(&reg->hr_all_item);
	spin_unlock(&o2hb_live_lock);

	kfree(reg);
}

static int o2hb_read_block_input(struct o2hb_region *reg,
				 const char *page,
				 size_t count,
				 unsigned long *ret_bytes,
				 unsigned int *ret_bits)
{
	unsigned long bytes;
	char *p = (char *)page;

	bytes = simple_strtoul(p, &p, 0);
	if (!p || (*p && (*p != '\n')))
		return -EINVAL;

	/* Heartbeat and fs min / max block sizes are the same. */
	if (bytes > 4096 || bytes < 512)
		return -ERANGE;
	if (hweight16(bytes) != 1)
		return -EINVAL;

	if (ret_bytes)
		*ret_bytes = bytes;
	if (ret_bits)
		*ret_bits = ffs(bytes) - 1;

	return 0;
}

static ssize_t o2hb_region_block_bytes_read(struct o2hb_region *reg,
					    char *page)
{
	return sprintf(page, "%u\n", reg->hr_block_bytes);
}

static ssize_t o2hb_region_block_bytes_write(struct o2hb_region *reg,
					     const char *page,
					     size_t count)
{
	int status;
	unsigned long block_bytes;
	unsigned int block_bits;

	if (reg->hr_bdev)
		return -EINVAL;

	status = o2hb_read_block_input(reg, page, count,
				       &block_bytes, &block_bits);
	if (status)
		return status;

	reg->hr_block_bytes = (unsigned int)block_bytes;
	reg->hr_block_bits = block_bits;

	return count;
}

static ssize_t o2hb_region_start_block_read(struct o2hb_region *reg,
					    char *page)
{
	return sprintf(page, "%llu\n", reg->hr_start_block);
}

static ssize_t o2hb_region_start_block_write(struct o2hb_region *reg,
					     const char *page,
					     size_t count)
{
	unsigned long long tmp;
	char *p = (char *)page;

	if (reg->hr_bdev)
		return -EINVAL;

	tmp = simple_strtoull(p, &p, 0);
	if (!p || (*p && (*p != '\n')))
		return -EINVAL;

	reg->hr_start_block = tmp;

	return count;
}

static ssize_t o2hb_region_blocks_read(struct o2hb_region *reg,
				       char *page)
{
	return sprintf(page, "%d\n", reg->hr_blocks);
}

static ssize_t o2hb_region_blocks_write(struct o2hb_region *reg,
					const char *page,
					size_t count)
{
	unsigned long tmp;
	char *p = (char *)page;

	if (reg->hr_bdev)
		return -EINVAL;

	tmp = simple_strtoul(p, &p, 0);
	if (!p || (*p && (*p != '\n')))
		return -EINVAL;

	if (tmp > O2NM_MAX_NODES || tmp == 0)
		return -ERANGE;

	reg->hr_blocks = (unsigned int)tmp;

	return count;
}

static ssize_t o2hb_region_dev_read(struct o2hb_region *reg,
				    char *page)
{
	unsigned int ret = 0;

	if (reg->hr_bdev)
		ret = sprintf(page, "%s\n", reg->hr_dev_name);

	return ret;
}

static void o2hb_init_region_params(struct o2hb_region *reg)
{
	reg->hr_slots_per_page = PAGE_CACHE_SIZE >> reg->hr_block_bits;
	reg->hr_timeout_ms = O2HB_REGION_TIMEOUT_MS;

	mlog(ML_HEARTBEAT, "hr_start_block = %llu, hr_blocks = %u\n",
	     reg->hr_start_block, reg->hr_blocks);
	mlog(ML_HEARTBEAT, "hr_block_bytes = %u, hr_block_bits = %u\n",
	     reg->hr_block_bytes, reg->hr_block_bits);
	mlog(ML_HEARTBEAT, "hr_timeout_ms = %u\n", reg->hr_timeout_ms);
	mlog(ML_HEARTBEAT, "dead threshold = %u\n", o2hb_dead_threshold);
}

static int o2hb_map_slot_data(struct o2hb_region *reg)
{
	int i, j;
	unsigned int last_slot;
	unsigned int spp = reg->hr_slots_per_page;
	struct page *page;
	char *raw;
	struct o2hb_disk_slot *slot;

	reg->hr_tmp_block = kmalloc(reg->hr_block_bytes, GFP_KERNEL);
	if (reg->hr_tmp_block == NULL) {
		mlog_errno(-ENOMEM);
		return -ENOMEM;
	}

	reg->hr_slots = kcalloc(reg->hr_blocks,
				sizeof(struct o2hb_disk_slot), GFP_KERNEL);
	if (reg->hr_slots == NULL) {
		mlog_errno(-ENOMEM);
		return -ENOMEM;
	}

	for(i = 0; i < reg->hr_blocks; i++) {
		slot = &reg->hr_slots[i];
		slot->ds_node_num = i;
		INIT_LIST_HEAD(&slot->ds_live_item);
		slot->ds_raw_block = NULL;
	}

	reg->hr_num_pages = (reg->hr_blocks + spp - 1) / spp;
	mlog(ML_HEARTBEAT, "Going to require %u pages to cover %u blocks "
			   "at %u blocks per page\n",
	     reg->hr_num_pages, reg->hr_blocks, spp);

	reg->hr_slot_data = kcalloc(reg->hr_num_pages, sizeof(struct page *),
				    GFP_KERNEL);
	if (!reg->hr_slot_data) {
		mlog_errno(-ENOMEM);
		return -ENOMEM;
	}

	for(i = 0; i < reg->hr_num_pages; i++) {
		page = alloc_page(GFP_KERNEL);
		if (!page) {
			mlog_errno(-ENOMEM);
			return -ENOMEM;
		}

		reg->hr_slot_data[i] = page;

		last_slot = i * spp;
		raw = page_address(page);
		for (j = 0;
		     (j < spp) && ((j + last_slot) < reg->hr_blocks);
		     j++) {
			BUG_ON((j + last_slot) >= reg->hr_blocks);

			slot = &reg->hr_slots[j + last_slot];
			slot->ds_raw_block =
				(struct o2hb_disk_heartbeat_block *) raw;

			raw += reg->hr_block_bytes;
		}
	}

	return 0;
}

/* Read in all the slots available and populate the tracking
 * structures so that we can start with a baseline idea of what's
 * there. */
static int o2hb_populate_slot_data(struct o2hb_region *reg)
{
	int ret, i;
	struct o2hb_disk_slot *slot;
	struct o2hb_disk_heartbeat_block *hb_block;

	mlog_entry_void();

	ret = o2hb_read_slots(reg, reg->hr_blocks);
	if (ret) {
		mlog_errno(ret);
		goto out;
	}

	/* We only want to get an idea of the values initially in each
	 * slot, so we do no verification - o2hb_check_slot will
	 * actually determine if each configured slot is valid and
	 * whether any values have changed. */
	for(i = 0; i < reg->hr_blocks; i++) {
		slot = &reg->hr_slots[i];
		hb_block = (struct o2hb_disk_heartbeat_block *) slot->ds_raw_block;

		/* Only fill the values that o2hb_check_slot uses to
		 * determine changing slots */
		slot->ds_last_time = le64_to_cpu(hb_block->hb_seq);
		slot->ds_last_generation = le64_to_cpu(hb_block->hb_generation);
	}

out:
	mlog_exit(ret);
	return ret;
}

/* this is acting as commit; we set up all of hr_bdev and hr_task or nothing */
static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
				     const char *page,
				     size_t count)
{
1638
	struct task_struct *hb_task;
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
	long fd;
	int sectsize;
	char *p = (char *)page;
	struct file *filp = NULL;
	struct inode *inode = NULL;
	ssize_t ret = -EINVAL;

	if (reg->hr_bdev)
		goto out;

	/* We can't heartbeat without having had our node number
	 * configured yet. */
	if (o2nm_this_node() == O2NM_MAX_NODES)
		goto out;

	fd = simple_strtol(p, &p, 0);
	if (!p || (*p && (*p != '\n')))
		goto out;

	if (fd < 0 || fd >= INT_MAX)
		goto out;

	filp = fget(fd);
	if (filp == NULL)
		goto out;

	if (reg->hr_blocks == 0 || reg->hr_start_block == 0 ||
	    reg->hr_block_bytes == 0)
		goto out;

	inode = igrab(filp->f_mapping->host);
	if (inode == NULL)
		goto out;

	if (!S_ISBLK(inode->i_mode))
		goto out;

	reg->hr_bdev = I_BDEV(filp->f_mapping->host);
1677
	ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ);
1678
1679
1680
1681
1682
1683
1684
1685
	if (ret) {
		reg->hr_bdev = NULL;
		goto out;
	}
	inode = NULL;

	bdevname(reg->hr_bdev, reg->hr_dev_name);

1686
	sectsize = bdev_logical_block_size(reg->hr_bdev);
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
	if (sectsize != reg->hr_block_bytes) {
		mlog(ML_ERROR,
		     "blocksize %u incorrect for device, expected %d",
		     reg->hr_block_bytes, sectsize);
		ret = -EINVAL;
		goto out;
	}

	o2hb_init_region_params(reg);

	/* Generation of zero is invalid */
	do {
		get_random_bytes(&reg->hr_generation,
				 sizeof(reg->hr_generation));
	} while (reg->hr_generation == 0);

	ret = o2hb_map_slot_data(reg);
	if (ret) {
		mlog_errno(ret);
		goto out;
	}

	ret = o2hb_populate_slot_data(reg);
	if (ret) {
		mlog_errno(ret);
		goto out;
	}

David Howells's avatar
David Howells committed
1715
	INIT_DELAYED_WORK(&reg->hr_write_timeout_work, o2hb_write_timeout);
1716
1717
1718
1719
1720
1721
1722
1723

	/*
	 * A node is considered live after it has beat LIVE_THRESHOLD
	 * times.  We're not steady until we've given them a chance
	 * _after_ our first read.
	 */
	atomic_set(&reg->hr_steady_iterations, O2HB_LIVE_THRESHOLD + 1);

1724
1725
1726
1727
	hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
			      reg->hr_item.ci_name);
	if (IS_ERR(hb_task)) {
		ret = PTR_ERR(hb_task);
1728
1729
1730
1731
		mlog_errno(ret);
		goto out;
	}

1732
1733
1734
1735
	spin_lock(&o2hb_live_lock);
	reg->hr_task = hb_task;
	spin_unlock(&o2hb_live_lock);

1736
1737
1738
	ret = wait_event_interruptible(o2hb_steady_queue,
				atomic_read(&reg->hr_steady_iterations) == 0);
	if (ret) {
1739
		/* We got interrupted (hello ptrace!).  Clean up */
1740
1741
		spin_lock(&o2hb_live_lock);
		hb_task = reg->hr_task;
1742
		reg->hr_task = NULL;
1743
1744
1745
1746
		spin_unlock(&o2hb_live_lock);

		if (hb_task)
			kthread_stop(hb_task);
1747
1748
1749
		goto out;
	}

1750
1751
1752
	/* Ok, we were woken.  Make sure it wasn't by drop_item() */
	spin_lock(&o2hb_live_lock);
	hb_task = reg->hr_task;
Sunil Mushran's avatar
   
Sunil Mushran committed
1753
1754
	if (o2hb_global_heartbeat_active())
		set_bit(reg->hr_region_num, o2hb_live_region_bitmap);
1755
1756
1757
1758
1759
1760
1761
	spin_unlock(&o2hb_live_lock);

	if (hb_task)
		ret = count;
	else
		ret = -EIO;

Sunil Mushran's avatar
   
Sunil Mushran committed
1762
1763
1764
1765
	if (hb_task && o2hb_global_heartbeat_active())
		printk(KERN_NOTICE "o2hb: Heartbeat started on region %s\n",
		       config_item_name(&reg->hr_item));

1766
1767
1768
1769
1770
1771
1772
out:
	if (filp)
		fput(filp);
	if (inode)
		iput(inode);
	if (ret < 0) {
		if (reg->hr_bdev) {
Al Viro's avatar
Al Viro committed
1773
			blkdev_put(reg->hr_bdev, FMODE_READ|FMODE_WRITE);
1774
1775
1776
1777
1778
1779
			reg->hr_bdev = NULL;
		}
	}
	return ret;
}

1780
1781
1782
static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
                                      char *page)
{
1783
1784
1785
1786
	pid_t pid = 0;

	spin_lock(&o2hb_live_lock);
	if (reg->hr_task)
1787
		pid = task_pid_nr(reg->hr_task);
1788
1789
1790
	spin_unlock(&o2hb_live_lock);

	if (!pid)
1791
1792
		return 0;

1793
	return sprintf(page, "%u\n", pid);
1794
1795
}

1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
struct o2hb_region_attribute {
	struct configfs_attribute attr;
	ssize_t (*show)(struct o2hb_region *, char *);
	ssize_t (*store)(struct o2hb_region *, const char *, size_t);
};

static struct o2hb_region_attribute o2hb_region_attr_block_bytes = {
	.attr	= { .ca_owner = THIS_MODULE,
		    .ca_name = "block_bytes",
		    .ca_mode = S_IRUGO | S_IWUSR },
	.show	= o2hb_region_block_bytes_read,
	.store	= o2hb_region_block_bytes_write,
};

static struct o2hb_region_attribute o2hb_region_attr_start_block = {
	.attr	= { .ca_owner = THIS_MODULE,
		    .ca_name = "start_block",
		    .ca_mode = S_IRUGO | S_IWUSR },
	.show	= o2hb_region_start_block_read,
	.store	= o2hb_region_start_block_write,
};

static struct o2hb_region_attribute o2hb_region_attr_blocks = {
	.attr	= { .ca_owner = THIS_MODULE,
		    .ca_name = "blocks",
		    .ca_mode = S_IRUGO | S_IWUSR },
	.show	= o2hb_region_blocks_read,
	.store	= o2hb_region_blocks_write,
};

static struct o2hb_region_attribute o2hb_region_attr_dev = {
	.attr	= { .ca_owner = THIS_MODULE,
		    .ca_name = "dev",
		    .ca_mode = S_IRUGO | S_IWUSR },
	.show	= o2hb_region_dev_read,
	.store	= o2hb_region_dev_write,
};

1834
1835
1836
1837
1838
1839
1840
static struct o2hb_region_attribute o2hb_region_attr_pid = {
       .attr   = { .ca_owner = THIS_MODULE,
                   .ca_name = "pid",
                   .ca_mode = S_IRUGO | S_IRUSR },
       .show   = o2hb_region_pid_read,
};