embox

Форк
0
439 строк · 8.8 Кб
1
/* @file
2
 * @brief  DumbFS driver
3
 * @author Denis Deryugin
4
 * @date   26 Dec 2014
5
 */
6

7
#include <errno.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <sys/stat.h>
11
#include <string.h>
12
#include <sys/types.h>
13
#include <limits.h>
14

15
#include <fs/dvfs.h>
16
#include <drivers/flash/flash.h>
17

18
#include <lib/libds/array.h>
19
#include <lib/libds/bitmap.h>
20
#include <util/math.h>
21

22
#include <fs/dfs.h>
23

24
#include <framework/mod/options.h>
25

26
#define DFS_MAGIC_0 0x0D
27
#define DFS_MAGIC_1 0xF5
28

29
#define MIN_FILE_SZ            OPTION_GET(NUMBER, minimum_file_size)
30

31
#define DFS_DENTRY_OFFSET(N) \
32
	((sizeof(struct dfs_sb_info)) + N * (sizeof(struct dfs_dir_entry)))
33

34
static int dfs_format(struct block_dev *bdev, void *priv) {
35
	uint8_t write_buf[sizeof(struct dfs_sb_info) + sizeof(struct dfs_dir_entry)];
36
	struct dfs_sb_info *sbi;
37
	struct dfs_dir_entry *root;
38
	struct flash_dev *fdev;
39
	int i, j, k;
40
	int err;
41

42
	fdev = flash_by_bdev(bdev);
43

44
	k = 0;
45
	for (j = 0; j < fdev->num_block_infos; j++) {
46
		for (i = 0; i < fdev->block_info[j].blocks; i++) {
47
			if ((err = flash_erase(fdev, k))) {
48
				return err;
49
			}
50
			k++;
51
		}
52
	}
53

54
	sbi  = (struct dfs_sb_info *)&write_buf[0];
55
	root = (struct dfs_dir_entry *)&write_buf[sizeof(struct dfs_sb_info)];
56
	
57
	/* Empty FS */
58
	*sbi = (struct dfs_sb_info) {
59
		.magic = {DFS_MAGIC_0, DFS_MAGIC_1},
60
		.inode_count = 1, /* Configure root directory */
61
		.max_inode_count = DFS_INODES_MAX + 1, /* + root folder with i_no 0 */
62
		.max_len = MIN_FILE_SZ,
63
		/* Set buffer block to the last one */
64
		.free_space = DFS_DENTRY_OFFSET(DFS_INODES_MAX),
65
	};
66

67
	strcpy((char *) root->name, "/");
68
	root->pos_start = sbi->free_space;
69
	root->len       = DFS_INODES_MAX;
70
	root->flags     = S_IFDIR;
71

72
	flash_write_aligned(fdev, 0, write_buf, sizeof(write_buf));
73

74
	return 0;
75
}
76

77
/*---------------------------------*\
78
 	File System Interface
79
\*---------------------------------*/
80

81
static int dfs_read_sb_info(struct super_block *sb, struct dfs_sb_info *sbi) {
82
	struct flash_dev *fdev;
83

84
	assert(sb);
85
	assert(sbi);
86

87
	fdev = flash_by_bdev(sb->bdev);
88

89
	flash_read_aligned(fdev, 0, sbi, sizeof(struct dfs_sb_info));
90

91
	return 0;
92
}
93

94
static int dfs_write_sb_info(struct super_block *sb, struct dfs_sb_info *sbi) {
95
	struct flash_dev *fdev;
96

97
	assert(sb);
98
	assert(sbi);
99

100
	fdev = flash_by_bdev(sb->bdev);
101
	
102
	flash_write_buffered(fdev, 0, sbi, sizeof(struct dfs_sb_info));
103

104
	return 0;
105
}
106

107
static int dfs_read_dirent(struct super_block *sb, int n, struct dfs_dir_entry *dtr) {
108
	struct flash_dev *fdev;
109
	uint32_t offt = DFS_DENTRY_OFFSET(n);
110

111
	assert(dtr);
112

113
	fdev = flash_by_bdev(sb->bdev);
114

115
	flash_read_aligned(fdev, offt, dtr, sizeof(struct dfs_dir_entry));
116

117
	if (dtr->name[0] == '\0') {
118
		return -ENOENT;
119
	}
120

121
	return 0;
122
}
123

124
static int dfs_write_dirent(struct super_block *sb, int n, struct dfs_dir_entry *dtr) {
125
	uint32_t offt = DFS_DENTRY_OFFSET(n);
126
	struct flash_dev *fdev;
127

128
	assert(dtr);
129

130
	fdev = flash_by_bdev(sb->bdev);
131

132
	flash_write_buffered(fdev, offt, dtr, sizeof(struct dfs_dir_entry));
133
	return 0;
134
}
135

136
static int ino_from_path(struct super_block *sb, const char *path) {
137
	struct dfs_dir_entry dirent;
138
	int i;
139

140
	assert(path);
141

142
	for (i = 0; i < DFS_INODES_MAX; i++) {
143
		if (!dfs_read_dirent(sb, i, &dirent) &&
144
				strcmp(path, (char *) dirent.name) == 0) {
145
			return i;
146
		}
147
	}
148

149
	return -1;
150
}
151

152
/***************
153
 New-VFS-related
154
 ***************/
155
static struct inode_operations dfs_iops;
156

157
static struct super_block_operations dfs_sbops = {
158
	.open_idesc = dvfs_file_open_idesc,
159
};
160

161
static int dfs_icreate(struct inode *i_new, struct inode *i_dir, int mode) {
162
	struct super_block *sb = i_dir->i_sb;
163
	struct dfs_sb_info *sbi = sb->sb_data;
164
	struct dfs_dir_entry dirent;
165

166
	assert(sb);
167
	assert(i_dir);
168

169
	if (i_new == NULL) {
170
		return -1;
171
	}
172

173
	dfs_read_sb_info(sb, sbi);
174

175
	if (sbi->inode_count > sbi->max_inode_count) {
176
		return -ENOMEM;
177
	}
178

179
	memset(&dirent, 0, sizeof(dirent));
180
	dirent = (struct dfs_dir_entry) {
181
		.pos_start = sbi->free_space,
182
		.len       = 0,
183
		.flags     = i_new->i_mode & S_IFMT,
184
	};
185

186
	strcpy((char *) dirent.name, inode_name(i_new));
187

188
	dfs_write_dirent(sb, sbi->inode_count, &dirent);
189

190
	*i_new = (struct inode) {
191
		.i_no      = sbi->inode_count,
192
		.i_privdata    = (void *) dirent.pos_start,
193
		.i_size    = 0,
194
		.i_sb      = sb,
195
		.i_ops     = &dfs_iops,
196
	};
197

198
	sbi->inode_count++;
199
	sbi->free_space += MIN_FILE_SZ;
200

201
	dfs_write_sb_info(sb, sbi);
202

203
	return 0;
204
}
205

206
/**
207
 * @brief Change size of file
208
 * @note In this FS we can only increase size
209
 *
210
 * @param inode
211
 * @param new_len
212
 *
213
 * @return Negative error number or 0 if succeed
214
 */
215
static int dfs_itruncate(struct inode *inode, off_t new_len) {
216
	struct super_block *sb;
217
	struct dfs_sb_info *sbi;
218
	struct dfs_dir_entry entry;
219

220
	assert(inode);
221

222
	if (new_len < 0) {
223
		return -1;
224
	}
225

226
	sb = inode->i_sb;
227
	sbi =sb->sb_data;
228

229
	if (new_len > sbi->max_len) {
230
		return -1;
231
	}
232

233
	dfs_read_dirent(sb, inode->i_no, &entry);
234
	if (new_len == inode->i_size) {
235
		/* No need to write changes on drive */
236
		return 0;
237
	}
238
	entry.len = new_len;
239
	dfs_write_dirent(sb, inode->i_no, &entry);
240

241
	inode->i_size = new_len;
242

243
	return 0;
244
}
245

246
static struct inode *dfs_ilookup(struct inode *inode, char const *path, struct inode const *dir) {
247
	struct dfs_dir_entry dirent;
248
	struct super_block *sb;
249

250
	assert(path);
251
	assert(dir);
252

253
	sb = dir->i_sb;
254

255
	inode->i_no = ino_from_path(sb, path);
256
	if (inode->i_no < 0) {
257
		return NULL;
258
	}
259

260
	dfs_read_dirent(sb, inode->i_no, &dirent);
261

262
	inode->i_privdata = (void *) (uintptr_t) dirent.pos_start;
263
	inode->i_size = dirent.len;
264
	inode->i_mode = dirent.flags;
265

266
	return inode;
267
}
268

269
static int dfs_iterate(struct inode *next, char *name_buf,
270
		struct inode *parent, struct dir_ctx *ctx) {
271
	struct super_block *sb;
272
	struct dfs_dir_entry dirent;
273
	int i, dir_pos;
274

275
	assert(ctx);
276
	assert(next);
277
	assert(parent);
278
	assert(name_buf);
279

280
	sb = parent->i_sb;
281

282
	dir_pos = (int) ctx->fs_ctx;
283
	if (dir_pos == 0) {
284
		dir_pos++; /*skip root dir */
285
	}
286

287
	for (i = dir_pos; i < parent->i_size; i++) {
288
		const uint32_t empty_dirent = 0xFFFFFFFF;
289

290
		dfs_read_dirent(sb, i, &dirent);
291
		if (memcmp(&dirent, &empty_dirent, sizeof(empty_dirent))) {
292
			*next = (struct inode) {
293
				.i_no   = i,
294
				.i_privdata = (void *) (uintptr_t) dirent.pos_start,
295
				.i_size = dirent.len,
296
				.i_sb   = sb,
297
				.i_ops  = &dfs_iops,
298
				.i_mode = dirent.flags,
299
			};
300
			ctx->fs_ctx = (void*) (i + 1);
301

302
			strncpy(name_buf, (char *) dirent.name, NAME_MAX);
303
			return 0;
304
		}
305
	}
306

307
	/* End of directory */
308
	return -1;
309
}
310

311
static struct inode_operations dfs_iops = {
312
	.ino_create   = dfs_icreate,
313
	.ino_lookup   = dfs_ilookup,
314

315
	.ino_iterate  = dfs_iterate,
316
	.ino_truncate = dfs_itruncate,
317
};
318

319
static struct file_operations dfs_fops;
320

321
static struct idesc *dfs_open(struct inode *node, struct idesc *desc, int __oflag) {
322
	struct file_desc *fdesc;
323

324
	if (!desc || !node) {
325
		SET_ERRNO(ENOENT);
326
		return NULL;
327
	}
328

329
	fdesc = (struct file_desc*)desc;
330
	fdesc->f_ops = &dfs_fops;
331

332
	return desc;
333
}
334

335
static int dfs_close(struct file_desc *desc) {
336
	return 0;
337
}
338

339
static size_t dfs_write(struct file_desc *desc, void *buf, size_t size) {
340
	int pos;
341
	int l;
342
	struct super_block *sb;
343
	struct dfs_sb_info *sbi;
344
	struct flash_dev *fdev;
345

346
	assert(desc);
347
	assert(desc->f_inode);
348
	assert(buf);
349

350
	sb = desc->f_inode->i_sb;
351
	sbi = sb->sb_data;
352
	fdev = flash_by_bdev(sb->bdev);
353

354
	pos = ((uintptr_t) desc->f_inode->i_privdata) + desc->f_pos;
355
	l = min(size, sbi->max_len - desc->f_pos);
356

357
	if (l <= 0) {
358
		return -1;
359
	}
360

361
	flash_write_buffered(fdev, pos, buf, l);
362

363
	return l;
364
}
365

366
static size_t dfs_read(struct file_desc *desc, void *buf, size_t size) {
367
	int pos;
368
	int l;
369
	struct super_block *sb;
370
	struct flash_dev *fdev;
371

372
	assert(desc);
373
	assert(desc->f_inode);
374
	assert(buf);
375

376
	sb = desc->f_inode->i_sb;
377
	fdev = flash_by_bdev(sb->bdev);
378

379
	pos = ((uintptr_t) desc->f_inode->i_privdata) + desc->f_pos;
380
	l = min(size, file_get_size(desc) - desc->f_pos);
381

382
	if (l < 0) {
383
		return -1;
384
	}
385

386
	flash_read_aligned(fdev, pos, buf, l);
387

388
	return l;
389
}
390

391
static struct file_operations dfs_fops = {
392
	.open = dfs_open,
393
	.close = dfs_close,
394
	.write = dfs_write,
395
	.read = dfs_read,
396
	.ioctl = NULL,
397
};
398

399
static struct dfs_sb_info dfs_info;
400

401
static int dfs_fill_sb(struct super_block *sb, const char *source) {
402
	struct dfs_dir_entry dtr;
403
	struct dfs_sb_info *sbi;
404

405
	sb->sb_ops     = &dfs_sbops;
406
	sb->sb_iops    = &dfs_iops;
407
	sb->sb_fops    = &dfs_fops;
408
	sb->sb_data    = &dfs_info;
409
	sb->bdev       = bdev_by_path(source);
410

411
	sbi = sb->sb_data;
412

413
	dfs_read_sb_info(sb, sbi);
414

415
	if (!(sbi->magic[0] == DFS_MAGIC_0 && sbi->magic[1] == DFS_MAGIC_1)) {
416
#if OPTION_GET(NUMBER, format_during_fill_sb)
417
		dfs_format(sb->bdev, NULL);
418
		dfs_read_sb_info(sb, sbi);
419
#else
420
		return -EINVAL;
421
#endif /* OPTION_GET(NUMBER, format_during_fill_sb) */
422
	}
423

424
	dfs_read_dirent(sb, 0, &dtr);
425

426
	sb->sb_root->i_no      = 0;
427
	sb->sb_root->i_size    = dtr.len;
428
	sb->sb_root->i_privdata    = (void *) ((uintptr_t) dtr.pos_start);
429

430
	return 0;
431
}
432

433
static const struct fs_driver dfs_dumb_driver = {
434
	.name      = "DumbFS",
435
	.fill_sb   = &dfs_fill_sb,
436
	.format    = dfs_format,
437
};
438

439
DECLARE_FILE_SYSTEM_DRIVER(dfs_dumb_driver);
440

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.