This repository has been archived by the owner on Dec 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlfs_fuse_bd.c
166 lines (136 loc) · 3.83 KB
/
lfs_fuse_bd.c
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
/*
* Linux user-space block device wrapper
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#define _GNU_SOURCE 1
#include "lfs_fuse_bd.h"
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <assert.h>
#include <malloc.h>
#include <arpa/inet.h>
#if !defined(__FreeBSD__)
#include <sys/ioctl.h>
#include <linux/fs.h>
#elif defined(__FreeBSD__)
#define BLKSSZGET DIOCGSECTORSIZE
#define BLKGETSIZE DIOCGMEDIASIZE
#include <sys/disk.h>
#endif
// Block device wrapper for user-space block devices
int lfs_fuse_bd_create(struct lfs_config *cfg, const char *path) {
int fd = open(path, O_RDWR | O_SYNC | O_DIRECT);
if (fd < 0) {
return -errno;
}
cfg->context = (void*)(intptr_t)fd;
// get sector size
if (!cfg->block_size) {
long ssize;
int err = ioctl(fd, BLKSSZGET, &ssize);
if (err) {
return -errno;
}
cfg->block_size = ssize;
}
// get size in sectors
if (!cfg->block_count) {
long size;
int err = ioctl(fd, BLKGETSIZE, &size);
if (err) {
return -errno;
}
cfg->block_count = size;
}
// setup function pointers
cfg->read = lfs_fuse_bd_read;
cfg->prog = lfs_fuse_bd_prog;
cfg->erase = lfs_fuse_bd_erase;
cfg->sync = lfs_fuse_bd_sync;
return 0;
}
void lfs_fuse_bd_destroy(const struct lfs_config *cfg) {
int fd = (intptr_t)cfg->context;
close(fd);
}
int lfs_fuse_bd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
int fd = (intptr_t)cfg->context;
// check if read is valid
assert(block < cfg->block_count);
// go to block
off_t err = lseek(fd, (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
if (err < 0) {
return -errno;
}
// read block
void *aligned = memalign(cfg->read_size, size);
ssize_t res = read(fd, aligned, (size_t)size);
if (res < 0) {
free(aligned);
return -errno;
}
memcpy(buffer, aligned, size);
free(aligned);
return 0;
}
int lfs_fuse_bd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
int fd = (intptr_t)cfg->context;
// check if write is valid
assert(block < cfg->block_count);
// go to block
off_t err = lseek(fd, (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
if (err < 0) {
return -errno;
}
// write block
void *aligned = memalign(cfg->prog_size, size);
memcpy(aligned, buffer, size);
ssize_t res = write(fd, aligned, (size_t)size);
if (res < 0) {
free(aligned);
return -errno;
}
free(aligned);
return 0;
}
int lfs_fuse_bd_erase(const struct lfs_config *cfg, lfs_block_t block) {
// Custom: erase requests are written to block 0 with buffer contents
// [ 0xdeadbeef, block_num_32b] in network byte order.
int fd = (intptr_t)cfg->context;
// check if erase is valid
assert(block < cfg->block_count);
// go to block 0
off_t err = lseek(fd, 0, SEEK_SET);
if (err < 0) {
return -errno;
}
// prepare buffer
uint32_t network;
uint8_t *aligned = memalign(cfg->prog_size, cfg->prog_size);
network = htonl(0xdeadbeef);
memcpy(aligned, &network, sizeof(network));
network = htonl(block);
memcpy(aligned + sizeof(network), &network, sizeof(network));
// write block to trigger erase
ssize_t res = write(fd, aligned, cfg->prog_size);
if (res < 0) {
free(aligned);
return -errno;
}
free(aligned);
return 0;
}
int lfs_fuse_bd_sync(const struct lfs_config *cfg) {
int fd = (intptr_t)cfg->context;
int err = fsync(fd);
if (err) {
return -errno;
}
return 0;
}