-
Notifications
You must be signed in to change notification settings - Fork 10
/
file.c
138 lines (112 loc) · 2.93 KB
/
file.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
#include <linux/uio.h>
#include "hdummy.h"
ssize_t dm_get_loffset(struct dm_inode *di, loff_t off)
{
ssize_t ret = DM_EMPTY_ENTRY;
loff_t add = 0;
u32 i = 0;
if (off > DM_DEFAULT_BSIZE)
add += DM_DEFAULT_BSIZE % off;
for (i = 0; i < DM_INODE_TSIZE; ++i) {
if (di->i_addrb[i] + off > di->i_addre[i]) {
off -= (di->i_addre[i] - di->i_addrb[i]);
} else {
ret = di->i_addrb[i] + off;
break;
}
}
BUG_ON(ret == 0xdeadbeef);
return ret;
}
ssize_t dummy_read(struct kiocb *iocb, struct iov_iter *to)
{
struct super_block *sb;
struct inode *inode;
struct dm_inode *dinode;
struct buffer_head *bh;
char *buffer;
void *buf = to->iov->iov_base;
int nbytes;
size_t count = iov_iter_count(to);
loff_t off = iocb->ki_pos;
loff_t end = off + count;
size_t blk = 0;
inode = iocb->ki_filp->f_path.dentry->d_inode;
sb = inode->i_sb;
dinode = inode->i_private;
if (off) {
return 0;
}
/* calculate datablock number here */
blk = dm_get_loffset(dinode, off);
bh = sb_bread(sb, blk);
if (!bh) {
printk(KERN_ERR "Failed to read data block %lu\n", blk);
return 0;
}
buffer = (char *)bh->b_data + (off % DM_DEFAULT_BSIZE);
nbytes = min((size_t)(dinode->i_size - off), count);
if (copy_to_user(buf, buffer, nbytes)) {
brelse(bh);
printk(KERN_ERR
"Error copying file content to userspace buffer\n");
return -EFAULT;
}
brelse(bh);
iocb->ki_pos += nbytes;
return nbytes;
}
ssize_t dm_alloc_if_necessary(struct dm_superblock *sb, struct dm_inode *di,
loff_t off, size_t cnt)
{
// Mock it until using bitmap
return 0;
}
ssize_t dummy_write(struct kiocb *iocb, struct iov_iter *from)
{
struct super_block *sb;
struct inode *inode;
struct dm_inode *dinode;
struct buffer_head *bh;
struct dm_superblock *dsb;
void *buf = from->iov->iov_base;
loff_t off = iocb->ki_pos;
size_t count = iov_iter_count(from);
size_t blk = 0;
size_t boff = 0;
char *buffer;
int ret;
inode = iocb->ki_filp->f_path.dentry->d_inode;
sb = inode->i_sb;
dinode = inode->i_private;
dsb = sb->s_fs_info;
ret = generic_write_checks(iocb, from);
if (ret <= 0) {
printk(KERN_INFO "DummyFS: generic_write_checks Failed: %d", ret);
return ret;
}
/* calculate datablock to write alloc if necessary */
blk = dm_alloc_if_necessary(dsb, dinode, off, count);
/* dummy files are contigous so offset can be easly calculated */
boff = dm_get_loffset(dinode, off);
bh = sb_bread(sb, boff);
if (!bh) {
printk(KERN_ERR "Failed to read data block %lu\n", blk);
return 0;
}
buffer = (char *)bh->b_data + (off % DM_DEFAULT_BSIZE);
if (copy_from_user(buffer, buf, count)) {
brelse(bh);
printk(KERN_ERR
"Error copying file content from userspace buffer "
"to kernel space\n");
return -EFAULT;
}
iocb->ki_pos += count;
mark_buffer_dirty(bh);
sync_dirty_buffer(bh);
brelse(bh);
dinode->i_size = max((size_t)(dinode->i_size), count);
dm_store_inode(sb, dinode);
return count;
}