aboutsummaryrefslogtreecommitdiffstats
path: root/libbcachefs.h
blob: b189a208115f63266f1bfeba6ac47ca43fc05c45 (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#ifndef _LIBBCACHE_H
#define _LIBBCACHE_H

#include <linux/uuid.h>
#include <stdbool.h>

#include "libbcachefs/bcachefs_format.h"
#include "libbcachefs/bcachefs_ioctl.h"
#include "libbcachefs/opts.h"
#include "libbcachefs/vstructs.h"
#include "tools-util.h"

/* option parsing */

#define SUPERBLOCK_SIZE_DEFAULT		2048	/* 1 MB */

struct bch_opt_strs {
union {
	char			*by_id[bch2_opts_nr];
struct {
#define x(_name, ...)	char	*_name;
	BCH_OPTS()
#undef x
};
};
};

void bch2_opt_strs_free(struct bch_opt_strs *);
struct bch_opt_strs bch2_cmdline_opts_get(int *, char *[], unsigned);
struct bch_opts bch2_parse_opts(struct bch_opt_strs);
void bch2_opts_usage(unsigned);

struct format_opts {
	char		*label;
	__uuid_t	uuid;
	unsigned	version;
	unsigned	superblock_size;
	bool		encrypted;
	char		*passphrase;
};

static inline struct format_opts format_opts_default()
{
	unsigned version = !access(   "/sys/module/bcachefs/parameters/version", R_OK)
	    ? read_file_u64(AT_FDCWD, "/sys/module/bcachefs/parameters/version")
	    : bcachefs_metadata_version_current;

	return (struct format_opts) {
		.version		= version,
		.superblock_size	= SUPERBLOCK_SIZE_DEFAULT,
	};
}

struct dev_opts {
	struct block_device *bdev;
	char		*path;
	u64		size;		/* bytes*/
	u64		bucket_size;	/* bytes */
	const char	*label;
	unsigned	data_allowed;
	unsigned	durability;
	bool		discard;

	u64		nbuckets;

	u64		sb_offset;
	u64		sb_end;
};

static inline struct dev_opts dev_opts_default()
{
	return (struct dev_opts) {
		.data_allowed		= ~0U << 2,
		.durability		= 1,
	};
}

u64 bch2_pick_bucket_size(struct bch_opts, struct dev_opts *);
void bch2_check_bucket_size(struct bch_opts, struct dev_opts *);

struct bch_sb *bch2_format(struct bch_opt_strs,
			   struct bch_opts,
			   struct format_opts, struct dev_opts *, size_t);

void bch2_super_write(int, struct bch_sb *);
struct bch_sb *__bch2_super_read(int, u64);

/* ioctl interface: */

int bcachectl_open(void);

struct bchfs_handle {
	__uuid_t	uuid;
	int		ioctl_fd;
	int		sysfs_fd;
};

void bcache_fs_close(struct bchfs_handle);
struct bchfs_handle bcache_fs_open(const char *);
struct bchfs_handle bchu_fs_open_by_dev(const char *, int *);
int bchu_dev_path_to_idx(struct bchfs_handle, const char *);

static inline void bchu_disk_add(struct bchfs_handle fs, char *dev)
{
	struct bch_ioctl_disk i = { .dev = (unsigned long) dev, };

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
}

static inline void bchu_disk_remove(struct bchfs_handle fs, unsigned dev_idx,
				    unsigned flags)
{
	struct bch_ioctl_disk i = {
		.flags	= flags|BCH_BY_INDEX,
		.dev	= dev_idx,
	};

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_REMOVE, &i);
}

static inline void bchu_disk_online(struct bchfs_handle fs, char *dev)
{
	struct bch_ioctl_disk i = { .dev = (unsigned long) dev, };

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ONLINE, &i);
}

static inline void bchu_disk_offline(struct bchfs_handle fs, unsigned dev_idx,
				     unsigned flags)
{
	struct bch_ioctl_disk i = {
		.flags	= flags|BCH_BY_INDEX,
		.dev	= dev_idx,
	};

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_OFFLINE, &i);
}

static inline void bchu_disk_set_state(struct bchfs_handle fs, unsigned dev,
				       unsigned new_state, unsigned flags)
{
	struct bch_ioctl_disk_set_state i = {
		.flags		= flags|BCH_BY_INDEX,
		.new_state	= new_state,
		.dev		= dev,
	};

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
}

static inline struct bch_ioctl_fs_usage *bchu_fs_usage(struct bchfs_handle fs)
{
	struct bch_ioctl_fs_usage *u = NULL;
	size_t replica_entries_bytes = 4096;

	while (1) {
		u = xrealloc(u, sizeof(*u) + replica_entries_bytes);
		u->replica_entries_bytes = replica_entries_bytes;

		if (!ioctl(fs.ioctl_fd, BCH_IOCTL_FS_USAGE, u))
			return u;

		if (errno != ERANGE)
			die("BCH_IOCTL_USAGE error: %m");

		replica_entries_bytes *= 2;
	}
}

static inline struct bch_ioctl_dev_usage_v2 *bchu_dev_usage(struct bchfs_handle fs,
							    unsigned idx)
{
	struct bch_ioctl_dev_usage_v2 *u = xcalloc(sizeof(*u) + sizeof(u->d[0]) * BCH_DATA_NR, 1);

	u->dev			= idx;
	u->flags		= BCH_BY_INDEX;
	u->nr_data_types	= BCH_DATA_NR;

	if (!ioctl(fs.ioctl_fd, BCH_IOCTL_DEV_USAGE_V2, u))
		return u;

	struct bch_ioctl_dev_usage u_v1 = { .dev = idx, .flags = BCH_BY_INDEX};
	xioctl(fs.ioctl_fd, BCH_IOCTL_DEV_USAGE, &u_v1);

	u->state	= u_v1.state;
	u->nr_data_types = ARRAY_SIZE(u_v1.d);
	u->bucket_size	= u_v1.bucket_size;
	u->nr_buckets	= u_v1.nr_buckets;

	for (unsigned i = 0; i < ARRAY_SIZE(u_v1.d); i++)
		u->d[i] = u_v1.d[i];

	return u;
}

static inline struct bch_sb *bchu_read_super(struct bchfs_handle fs, unsigned idx)
{
	size_t size = 4096;
	struct bch_sb *sb = NULL;

	while (1) {
		sb = xrealloc(sb, size);
		struct bch_ioctl_read_super i = {
			.size	= size,
			.sb	= (unsigned long) sb,
		};

		if (idx != -1) {
			i.flags |= BCH_READ_DEV|BCH_BY_INDEX;
			i.dev = idx;
		}

		if (!ioctl(fs.ioctl_fd, BCH_IOCTL_READ_SUPER, &i))
			return sb;
		if (errno != ERANGE)
			die("BCH_IOCTL_READ_SUPER error: %m");
		size *= 2;
	}
}

static inline unsigned bchu_disk_get_idx(struct bchfs_handle fs, dev_t dev)
{
	struct bch_ioctl_disk_get_idx i = { .dev = dev };

	return xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_GET_IDX, &i);
}

static inline void bchu_disk_resize(struct bchfs_handle fs,
				    unsigned idx,
				    u64 nbuckets)
{
	struct bch_ioctl_disk_resize i = {
		.flags	= BCH_BY_INDEX,
		.dev	= idx,
		.nbuckets = nbuckets,
	};

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_RESIZE, &i);
}

static inline void bchu_disk_resize_journal(struct bchfs_handle fs,
					    unsigned idx,
					    u64 nbuckets)
{
	struct bch_ioctl_disk_resize i = {
		.flags	= BCH_BY_INDEX,
		.dev	= idx,
		.nbuckets = nbuckets,
	};

	xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_RESIZE_JOURNAL, &i);
}

int bchu_data(struct bchfs_handle, struct bch_ioctl_data);

struct dev_name {
	unsigned	idx;
	char		*dev;
	char		*label;
	uuid_t		uuid;
	unsigned	durability;
};
typedef DARRAY(struct dev_name) dev_names;

dev_names bchu_fs_get_devices(struct bchfs_handle);

#endif /* _LIBBCACHE_H */