-
Notifications
You must be signed in to change notification settings - Fork 1
/
inode_vfslib.c
121 lines (104 loc) · 2.75 KB
/
inode_vfslib.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
/*
* Copied some vfs library functions to add change_{begin,end} and
* tux3_iattrdirty().
*
* We should check the update of original functions, and sync with it.
*/
#include <linux/splice.h>
#include <linux/aio.h> /* for kiocb */
/*
* Almost copy of generic_file_aio_write() (added changed_begin/end,
* tux3_iattrdirty()).
*/
static ssize_t tux3_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
if(DEBUG_MODE_K==1)
{
printk(KERN_INFO"%25s %25s %4d #in\n",__FILE__,__func__,__LINE__);
}
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
struct sb *sb = tux_sb(inode->i_sb);
struct blk_plug plug;
ssize_t ret;
BUG_ON(iocb->ki_pos != pos);
mutex_lock(&inode->i_mutex);
blk_start_plug(&plug);
/* For each ->write_end() calls change_end(). */
change_begin(sb);
/* For timestamp. FIXME: convert this to ->update_time handler? */
tux3_iattrdirty(inode);
ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
change_end_if_needed(sb);
mutex_unlock(&inode->i_mutex);
if (ret > 0 || ret == -EIOCBQUEUED) {
ssize_t err;
err = generic_write_sync(file, pos, ret);
if (err < 0 && ret > 0)
ret = err;
}
blk_finish_plug(&plug);
return ret;
}
/*
* Almost copy of generic_file_splice_write() (added changed_begin/end,
* tux3_iattrdirty()).
*/
static ssize_t tux3_file_splice_write(struct pipe_inode_info *pipe,
struct file *out, loff_t *ppos,
size_t len, unsigned int flags)
{
if(DEBUG_MODE_K==1)
{
printk(KERN_INFO"%25s %25s %4d #in\n",__FILE__,__func__,__LINE__);
}
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
struct sb *sb = tux_sb(inode->i_sb);
struct splice_desc sd = {
.total_len = len,
.flags = flags,
.pos = *ppos,
.u.file = out,
};
ssize_t ret;
sb_start_write(inode->i_sb);
pipe_lock(pipe);
splice_from_pipe_begin(&sd);
do {
ret = splice_from_pipe_next(pipe, &sd);
if (ret <= 0)
break;
mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
/* For each ->write_end() calls change_end(). */
change_begin(sb);
/* For timestamp. FIXME: convert this to ->update_time
* handler? */
tux3_iattrdirty(inode);
ret = file_remove_suid(out);
if (!ret) {
ret = file_update_time(out);
if (!ret)
ret = splice_from_pipe_feed(pipe, &sd,
pipe_to_file);
}
change_end_if_needed(sb);
mutex_unlock(&inode->i_mutex);
} while (ret > 0);
splice_from_pipe_end(pipe, &sd);
pipe_unlock(pipe);
if (sd.num_spliced)
ret = sd.num_spliced;
if (ret > 0) {
int err;
err = generic_write_sync(out, *ppos, ret);
if (err)
ret = err;
else
*ppos += ret;
balance_dirty_pages_ratelimited(mapping);
}
sb_end_write(inode->i_sb);
return ret;
}