summaryrefslogtreecommitdiff
path: root/include/linux/dm-dirty-log.h
blob: 0b10faedb26a6186b9ae215f73fab2ff99dbec94 (plain)
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2003 Sistina Software
 * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
 *
 * Device-Mapper dirty region log.
 *
 * This file is released under the LGPL.
 */

#ifndef _LINUX_DM_DIRTY_LOG
#define _LINUX_DM_DIRTY_LOG

#ifdef __KERNEL__

#include <linux/types.h>
#include <linux/device-mapper.h>

typedef sector_t region_t;

struct dm_dirty_log_type;

struct dm_dirty_log {
	struct dm_dirty_log_type *type;
	int (*flush_callback_fn)(struct dm_target *ti);
	void *context;
};

struct dm_dirty_log_type {
	const char *name;
	struct module *module;

	/* For internal device-mapper use */
	struct list_head list;

	int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
		   unsigned int argc, char **argv);
	void (*dtr)(struct dm_dirty_log *log);

	/*
	 * There are times when we don't want the log to touch
	 * the disk.
	 */
	int (*presuspend)(struct dm_dirty_log *log);
	int (*postsuspend)(struct dm_dirty_log *log);
	int (*resume)(struct dm_dirty_log *log);

	/*
	 * Retrieves the smallest size of region that the log can
	 * deal with.
	 */
	uint32_t (*get_region_size)(struct dm_dirty_log *log);

	/*
	 * A predicate to say whether a region is clean or not.
	 * May block.
	 */
	int (*is_clean)(struct dm_dirty_log *log, region_t region);

	/*
	 *  Returns: 0, 1, -EWOULDBLOCK, < 0
	 *
	 * A predicate function to check the area given by
	 * [sector, sector + len) is in sync.
	 *
	 * If -EWOULDBLOCK is returned the state of the region is
	 * unknown, typically this will result in a read being
	 * passed to a daemon to deal with, since a daemon is
	 * allowed to block.
	 */
	int (*in_sync)(struct dm_dirty_log *log, region_t region,
		       int can_block);

	/*
	 * Flush the current log state (eg, to disk).  This
	 * function may block.
	 */
	int (*flush)(struct dm_dirty_log *log);

	/*
	 * Mark an area as clean or dirty.  These functions may
	 * block, though for performance reasons blocking should
	 * be extremely rare (eg, allocating another chunk of
	 * memory for some reason).
	 */
	void (*mark_region)(struct dm_dirty_log *log, region_t region);
	void (*clear_region)(struct dm_dirty_log *log, region_t region);

	/*
	 * Returns: <0 (error), 0 (no region), 1 (region)
	 *
	 * The mirrord will need perform recovery on regions of
	 * the mirror that are in the NOSYNC state.  This
	 * function asks the log to tell the caller about the
	 * next region that this machine should recover.
	 *
	 * Do not confuse this function with 'in_sync()', one
	 * tells you if an area is synchronised, the other
	 * assigns recovery work.
	 */
	int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);

	/*
	 * This notifies the log that the resync status of a region
	 * has changed.  It also clears the region from the recovering
	 * list (if present).
	 */
	void (*set_region_sync)(struct dm_dirty_log *log,
				region_t region, int in_sync);

	/*
	 * Returns the number of regions that are in sync.
	 */
	region_t (*get_sync_count)(struct dm_dirty_log *log);

	/*
	 * Support function for mirror status requests.
	 */
	int (*status)(struct dm_dirty_log *log, status_type_t status_type,
		      char *result, unsigned int maxlen);

	/*
	 * is_remote_recovering is necessary for cluster mirroring. It provides
	 * a way to detect recovery on another node, so we aren't writing
	 * concurrently.  This function is likely to block (when a cluster log
	 * is used).
	 *
	 * Returns: 0, 1
	 */
	int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
};

int dm_dirty_log_type_register(struct dm_dirty_log_type *type);
int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type);

/*
 * Make sure you use these two functions, rather than calling
 * type->constructor/destructor() directly.
 */
struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
			struct dm_target *ti,
			int (*flush_callback_fn)(struct dm_target *ti),
			unsigned int argc, char **argv);
void dm_dirty_log_destroy(struct dm_dirty_log *log);

#endif	/* __KERNEL__ */
#endif	/* _LINUX_DM_DIRTY_LOG_H */