Skip to content

Commit f4ab9d9

Browse files
projectgusdpgeorge
authored andcommitted
extmod/vfs_blockdev: Implement common helper for read and write.
- Code size saving as all of these functions are very similar. - Resolves the "TODO" of the plain read and write functions not propagating errors. An error in the underlying block device now causes VFatFs to return EIO, for example. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <[email protected]>
1 parent 4f6d4b2 commit f4ab9d9

File tree

3 files changed

+40
-51
lines changed

3 files changed

+40
-51
lines changed

extmod/vfs_blockdev.c

+25-38
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,6 @@
3232

3333
#if MICROPY_VFS
3434

35-
// Block device functions are expected to return 0 on success
36-
// and negative integer on errors. Check for positive integer
37-
// results as some callers (i.e. littlefs) will produce corrupt
38-
// results from these.
39-
static int mp_vfs_check_result(mp_obj_t ret) {
40-
if (ret == mp_const_none) {
41-
return 0;
42-
} else {
43-
int i = MP_OBJ_SMALL_INT_VALUE(ret);
44-
return i > 0 ? (-MP_EINVAL) : i;
45-
}
46-
}
47-
4835
void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) {
4936
mp_load_method(bdev, MP_QSTR_readblocks, self->readblocks);
5037
mp_load_method_maybe(bdev, MP_QSTR_writeblocks, self->writeblocks);
@@ -59,27 +46,38 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) {
5946
}
6047
}
6148

49+
// Helper function to minimise code size of read/write functions
50+
// note the n_args argument is moved to the end for further code size reduction (args keep same position in caller and callee).
51+
static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t block_off, size_t len, void *buf, size_t n_args) {
52+
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf};
53+
args[2] = MP_OBJ_NEW_SMALL_INT(block_num);
54+
args[3] = MP_OBJ_FROM_PTR(&ar);
55+
args[4] = MP_OBJ_NEW_SMALL_INT(block_off); // ignored for n_args == 2
56+
mp_obj_t ret = mp_call_method_n_kw(n_args, 0, args);
57+
58+
if (ret == mp_const_none) {
59+
return 0;
60+
} else {
61+
// Block device functions are expected to return 0 on success
62+
// and negative integer on errors. Check for positive integer
63+
// results as some callers (i.e. littlefs) will produce corrupt
64+
// results from these.
65+
int i = MP_OBJ_SMALL_INT_VALUE(ret);
66+
return i > 0 ? (-MP_EINVAL) : i;
67+
}
68+
}
69+
6270
int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) {
6371
if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
6472
mp_uint_t (*f)(uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2];
6573
return f(buf, block_num, num_blocks);
6674
} else {
67-
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, buf};
68-
self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
69-
self->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
70-
mp_call_method_n_kw(2, 0, self->readblocks);
71-
// TODO handle error return
72-
return 0;
75+
return mp_vfs_blockdev_call_rw(self->readblocks, block_num, 0, num_blocks * self->block_size, buf, 2);
7376
}
7477
}
7578

7679
int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf) {
77-
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf};
78-
self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
79-
self->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
80-
self->readblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off);
81-
mp_obj_t ret = mp_call_method_n_kw(3, 0, self->readblocks);
82-
return mp_vfs_check_result(ret);
80+
return mp_vfs_blockdev_call_rw(self->readblocks, block_num, block_off, len, buf, 3);
8381
}
8482

8583
int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf) {
@@ -92,12 +90,7 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_
9290
mp_uint_t (*f)(const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2];
9391
return f(buf, block_num, num_blocks);
9492
} else {
95-
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, (void *)buf};
96-
self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
97-
self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
98-
mp_call_method_n_kw(2, 0, self->writeblocks);
99-
// TODO handle error return
100-
return 0;
93+
return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, 0, num_blocks * self->block_size, (void *)buf, 2);
10194
}
10295
}
10396

@@ -106,13 +99,7 @@ int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t
10699
// read-only block device
107100
return -MP_EROFS;
108101
}
109-
110-
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, (void *)buf};
111-
self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
112-
self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
113-
self->writeblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off);
114-
mp_obj_t ret = mp_call_method_n_kw(3, 0, self->writeblocks);
115-
return mp_vfs_check_result(ret);
102+
return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, block_off, len, (void *)buf, 3);
116103
}
117104

118105
mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) {

tests/extmod/vfs_blockdev_invalid.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ def ioctl(self, op, arg):
5252

5353
def test(vfs_class):
5454
print(vfs_class)
55+
bdev.read_res = 0 # reset function results
56+
bdev.write_res = 0
5557

5658
vfs_class.mkfs(bdev)
5759
fs = vfs_class(bdev)
@@ -84,4 +86,4 @@ def test(vfs_class):
8486

8587

8688
test(vfs.VfsLfs2)
87-
test(vfs.VfsFat) # Looks like most failures of underlying device are ignored by VFAT currently
89+
test(vfs.VfsFat)

tests/extmod/vfs_blockdev_invalid.py.exp

+12-12
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,22 @@ readblocks
105105
read 1 a
106106
read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
107107
readblocks
108-
opened
108+
OSError [Errno 5] EIO
109109
readblocks
110-
read 1 a
111-
read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
112110
readblocks
113-
opened
111+
OSError [Errno 5] EIO
114112
readblocks
115-
read 1 a
116-
read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
113+
OSError [Errno 5] EIO
117114
readblocks
118-
opened
119115
readblocks
120-
read 1 a
121-
read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
116+
OSError [Errno 5] EIO
122117
readblocks
123-
opened
118+
OSError [Errno 5] EIO
124119
readblocks
125-
read 1 a
126-
read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
120+
readblocks
121+
OSError [Errno 5] EIO
122+
readblocks
123+
OSError [Errno 5] EIO
124+
readblocks
125+
readblocks
126+
OSError [Errno 5] EIO

0 commit comments

Comments
 (0)