提交 8659ac25 编写于 作者: T Tiger Yang 提交者: Mark Fasheh

ocfs2: Add splice support

Add splice read/write support in ocfs2.

ocfs2_file_splice_read/write are very similar to ocfs2_file_aio_read/write.
Signed-off-by: NTiger Yang <tiger.yang@oracle.com>
Signed-off-by: NMark Fasheh <mark.fasheh@oracle.com>
上级 e88d0c9a
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/pipe_fs_i.h>
#define MLOG_MASK_PREFIX ML_INODE #define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h> #include <cluster/masklog.h>
...@@ -943,53 +944,21 @@ static int ocfs2_write_remove_suid(struct inode *inode) ...@@ -943,53 +944,21 @@ static int ocfs2_write_remove_suid(struct inode *inode)
return ret; return ret;
} }
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
const struct iovec *iov, loff_t *ppos,
unsigned long nr_segs, size_t count,
loff_t pos) int appending)
{ {
int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0; int ret = 0, meta_level = appending;
struct inode *inode = dentry->d_inode;
u32 clusters; u32 clusters;
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
loff_t newsize, saved_pos; loff_t newsize, saved_pos;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
filp->f_dentry->d_name.len,
filp->f_dentry->d_name.name);
/* happy write of zero bytes */
if (iocb->ki_left == 0)
return 0;
if (!inode) {
mlog(0, "bad inode\n");
return -EIO;
}
mutex_lock(&inode->i_mutex);
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
if (filp->f_flags & O_DIRECT) {
have_alloc_sem = 1;
down_read(&inode->i_alloc_sem);
}
/* concurrent O_DIRECT writes are allowed */
rw_level = (filp->f_flags & O_DIRECT) ? 0 : 1;
ret = ocfs2_rw_lock(inode, rw_level);
if (ret < 0) {
rw_level = -1;
mlog_errno(ret);
goto out;
}
/* /*
* We sample i_size under a read level meta lock to see if our write * We sample i_size under a read level meta lock to see if our write
* is extending the file, if it is we back off and get a write level * is extending the file, if it is we back off and get a write level
* meta lock. * meta lock.
*/ */
meta_level = (filp->f_flags & O_APPEND) ? 1 : 0;
for(;;) { for(;;) {
ret = ocfs2_meta_lock(inode, NULL, meta_level); ret = ocfs2_meta_lock(inode, NULL, meta_level);
if (ret < 0) { if (ret < 0) {
...@@ -1007,7 +976,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ...@@ -1007,7 +976,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
* inode. There's also the dinode i_size state which * inode. There's also the dinode i_size state which
* can be lost via setattr during extending writes (we * can be lost via setattr during extending writes (we
* set inode->i_size at the end of a write. */ * set inode->i_size at the end of a write. */
if (should_remove_suid(filp->f_dentry)) { if (should_remove_suid(dentry)) {
if (meta_level == 0) { if (meta_level == 0) {
ocfs2_meta_unlock(inode, meta_level); ocfs2_meta_unlock(inode, meta_level);
meta_level = 1; meta_level = 1;
...@@ -1017,19 +986,19 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ...@@ -1017,19 +986,19 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
ret = ocfs2_write_remove_suid(inode); ret = ocfs2_write_remove_suid(inode);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out_unlock;
} }
} }
/* work on a copy of ppos until we're sure that we won't have /* work on a copy of ppos until we're sure that we won't have
* to recalculate it due to relocking. */ * to recalculate it due to relocking. */
if (filp->f_flags & O_APPEND) { if (appending) {
saved_pos = i_size_read(inode); saved_pos = i_size_read(inode);
mlog(0, "O_APPEND: inode->i_size=%llu\n", saved_pos); mlog(0, "O_APPEND: inode->i_size=%llu\n", saved_pos);
} else { } else {
saved_pos = iocb->ki_pos; saved_pos = *ppos;
} }
newsize = iocb->ki_left + saved_pos; newsize = count + saved_pos;
mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
(long long) saved_pos, (long long) newsize, (long long) saved_pos, (long long) newsize,
...@@ -1062,19 +1031,66 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ...@@ -1062,19 +1031,66 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
if (!clusters) if (!clusters)
break; break;
ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left); ret = ocfs2_extend_file(inode, NULL, newsize, count);
if (ret < 0) { if (ret < 0) {
if (ret != -ENOSPC) if (ret != -ENOSPC)
mlog_errno(ret); mlog_errno(ret);
goto out; goto out_unlock;
} }
break; break;
} }
/* ok, we're done with i_size and alloc work */ if (appending)
iocb->ki_pos = saved_pos; *ppos = saved_pos;
out_unlock:
ocfs2_meta_unlock(inode, meta_level); ocfs2_meta_unlock(inode, meta_level);
meta_level = -1;
out:
return ret;
}
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
loff_t pos)
{
int ret, rw_level, have_alloc_sem = 0;
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
int appending = filp->f_flags & O_APPEND ? 1 : 0;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
filp->f_dentry->d_name.len,
filp->f_dentry->d_name.name);
/* happy write of zero bytes */
if (iocb->ki_left == 0)
return 0;
mutex_lock(&inode->i_mutex);
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
if (filp->f_flags & O_DIRECT) {
have_alloc_sem = 1;
down_read(&inode->i_alloc_sem);
}
/* concurrent O_DIRECT writes are allowed */
rw_level = (filp->f_flags & O_DIRECT) ? 0 : 1;
ret = ocfs2_rw_lock(inode, rw_level);
if (ret < 0) {
rw_level = -1;
mlog_errno(ret);
goto out;
}
ret = ocfs2_prepare_inode_for_write(filp->f_dentry, &iocb->ki_pos,
iocb->ki_left, appending);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
/* communicate with ocfs2_dio_end_io */ /* communicate with ocfs2_dio_end_io */
ocfs2_iocb_set_rw_locked(iocb); ocfs2_iocb_set_rw_locked(iocb);
...@@ -1100,8 +1116,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ...@@ -1100,8 +1116,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
} }
out: out:
if (meta_level != -1)
ocfs2_meta_unlock(inode, meta_level);
if (have_alloc_sem) if (have_alloc_sem)
up_read(&inode->i_alloc_sem); up_read(&inode->i_alloc_sem);
if (rw_level != -1) if (rw_level != -1)
...@@ -1112,6 +1126,77 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ...@@ -1112,6 +1126,77 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
return ret; return ret;
} }
static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
struct file *out,
loff_t *ppos,
size_t len,
unsigned int flags)
{
int ret;
struct inode *inode = out->f_dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe,
(unsigned int)len,
out->f_dentry->d_name.len,
out->f_dentry->d_name.name);
inode_double_lock(inode, pipe->inode);
ret = ocfs2_rw_lock(inode, 1);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
ret = ocfs2_prepare_inode_for_write(out->f_dentry, ppos, len, 0);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
}
/* ok, we're done with i_size and alloc work */
ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags);
out_unlock:
ocfs2_rw_unlock(inode, 1);
out:
inode_double_unlock(inode, pipe->inode);
mlog_exit(ret);
return ret;
}
static ssize_t ocfs2_file_splice_read(struct file *in,
loff_t *ppos,
struct pipe_inode_info *pipe,
size_t len,
unsigned int flags)
{
int ret = 0;
struct inode *inode = in->f_dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe,
(unsigned int)len,
in->f_dentry->d_name.len,
in->f_dentry->d_name.name);
/*
* See the comment in ocfs2_file_aio_read()
*/
ret = ocfs2_meta_lock(inode, NULL, 0);
if (ret < 0) {
mlog_errno(ret);
goto bail;
}
ocfs2_meta_unlock(inode, 0);
ret = generic_file_splice_read(in, ppos, pipe, len, flags);
bail:
mlog_exit(ret);
return ret;
}
static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
const struct iovec *iov, const struct iovec *iov,
unsigned long nr_segs, unsigned long nr_segs,
...@@ -1210,6 +1295,8 @@ const struct file_operations ocfs2_fops = { ...@@ -1210,6 +1295,8 @@ const struct file_operations ocfs2_fops = {
.aio_read = ocfs2_file_aio_read, .aio_read = ocfs2_file_aio_read,
.aio_write = ocfs2_file_aio_write, .aio_write = ocfs2_file_aio_write,
.ioctl = ocfs2_ioctl, .ioctl = ocfs2_ioctl,
.splice_read = ocfs2_file_splice_read,
.splice_write = ocfs2_file_splice_write,
}; };
const struct file_operations ocfs2_dops = { const struct file_operations ocfs2_dops = {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册