blob: cc096230859875a033d9a1969ab0a12d29f0c7eb [file] [log] [blame]
/*
* 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)
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
struct sb *sb = tux_sb(inode->i_sb);
ssize_t ret;
BUG_ON(iocb->ki_pos != pos);
mutex_lock(&inode->i_mutex);
/* 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) {
ssize_t err;
err = generic_write_sync(file, iocb->ki_pos - ret, ret);
if (err < 0)
ret = err;
}
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)
{
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;
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);
}
return ret;
}