|
@@ -1881,143 +1881,13 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static inline void
|
|
|
-ocfs2_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
|
|
|
-{
|
|
|
- const struct iovec *iov = *iovp;
|
|
|
- size_t base = *basep;
|
|
|
-
|
|
|
- do {
|
|
|
- int copy = min(bytes, iov->iov_len - base);
|
|
|
-
|
|
|
- bytes -= copy;
|
|
|
- base += copy;
|
|
|
- if (iov->iov_len == base) {
|
|
|
- iov++;
|
|
|
- base = 0;
|
|
|
- }
|
|
|
- } while (bytes);
|
|
|
- *iovp = iov;
|
|
|
- *basep = base;
|
|
|
-}
|
|
|
-
|
|
|
-static struct page * ocfs2_get_write_source(char **ret_src_buf,
|
|
|
- const struct iovec *cur_iov,
|
|
|
- size_t iov_offset)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- char *buf = cur_iov->iov_base + iov_offset;
|
|
|
- struct page *src_page = NULL;
|
|
|
- unsigned long off;
|
|
|
-
|
|
|
- off = (unsigned long)(buf) & ~PAGE_CACHE_MASK;
|
|
|
-
|
|
|
- if (!segment_eq(get_fs(), KERNEL_DS)) {
|
|
|
- /*
|
|
|
- * Pull in the user page. We want to do this outside
|
|
|
- * of the meta data locks in order to preserve locking
|
|
|
- * order in case of page fault.
|
|
|
- */
|
|
|
- ret = get_user_pages(current, current->mm,
|
|
|
- (unsigned long)buf & PAGE_CACHE_MASK, 1,
|
|
|
- 0, 0, &src_page, NULL);
|
|
|
- if (ret == 1)
|
|
|
- *ret_src_buf = kmap(src_page) + off;
|
|
|
- else
|
|
|
- src_page = ERR_PTR(-EFAULT);
|
|
|
- } else {
|
|
|
- *ret_src_buf = buf;
|
|
|
- }
|
|
|
-
|
|
|
- return src_page;
|
|
|
-}
|
|
|
-
|
|
|
-static void ocfs2_put_write_source(struct page *page)
|
|
|
-{
|
|
|
- if (page) {
|
|
|
- kunmap(page);
|
|
|
- page_cache_release(page);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
|
|
|
- const struct iovec *iov,
|
|
|
- unsigned long nr_segs,
|
|
|
- size_t count,
|
|
|
- ssize_t o_direct_written)
|
|
|
-{
|
|
|
- int ret = 0;
|
|
|
- ssize_t copied, total = 0;
|
|
|
- size_t iov_offset = 0, bytes;
|
|
|
- loff_t pos;
|
|
|
- const struct iovec *cur_iov = iov;
|
|
|
- struct page *user_page, *page;
|
|
|
- char * uninitialized_var(buf);
|
|
|
- char *dst;
|
|
|
- void *fsdata;
|
|
|
-
|
|
|
- /*
|
|
|
- * handle partial DIO write. Adjust cur_iov if needed.
|
|
|
- */
|
|
|
- ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written);
|
|
|
-
|
|
|
- do {
|
|
|
- pos = *ppos;
|
|
|
-
|
|
|
- user_page = ocfs2_get_write_source(&buf, cur_iov, iov_offset);
|
|
|
- if (IS_ERR(user_page)) {
|
|
|
- ret = PTR_ERR(user_page);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- /* Stay within our page boundaries */
|
|
|
- bytes = min((PAGE_CACHE_SIZE - ((unsigned long)pos & ~PAGE_CACHE_MASK)),
|
|
|
- (PAGE_CACHE_SIZE - ((unsigned long)buf & ~PAGE_CACHE_MASK)));
|
|
|
- /* Stay within the vector boundary */
|
|
|
- bytes = min_t(size_t, bytes, cur_iov->iov_len - iov_offset);
|
|
|
- /* Stay within count */
|
|
|
- bytes = min(bytes, count);
|
|
|
-
|
|
|
- page = NULL;
|
|
|
- ret = ocfs2_write_begin(file, file->f_mapping, pos, bytes, 0,
|
|
|
- &page, &fsdata);
|
|
|
- if (ret) {
|
|
|
- mlog_errno(ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- dst = kmap_atomic(page, KM_USER0);
|
|
|
- memcpy(dst + (pos & (loff_t)(PAGE_CACHE_SIZE - 1)), buf, bytes);
|
|
|
- kunmap_atomic(dst, KM_USER0);
|
|
|
- flush_dcache_page(page);
|
|
|
- ocfs2_put_write_source(user_page);
|
|
|
-
|
|
|
- copied = ocfs2_write_end(file, file->f_mapping, pos, bytes,
|
|
|
- bytes, page, fsdata);
|
|
|
- if (copied < 0) {
|
|
|
- mlog_errno(copied);
|
|
|
- ret = copied;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- total += copied;
|
|
|
- *ppos = pos + copied;
|
|
|
- count -= copied;
|
|
|
-
|
|
|
- ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied);
|
|
|
- } while(count);
|
|
|
-
|
|
|
-out:
|
|
|
- return total ? total : ret;
|
|
|
-}
|
|
|
-
|
|
|
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
|
|
const struct iovec *iov,
|
|
|
unsigned long nr_segs,
|
|
|
loff_t pos)
|
|
|
{
|
|
|
int ret, direct_io, appending, rw_level, have_alloc_sem = 0;
|
|
|
- int can_do_direct, sync = 0;
|
|
|
+ int can_do_direct;
|
|
|
ssize_t written = 0;
|
|
|
size_t ocount; /* original count */
|
|
|
size_t count; /* after file limit checks */
|
|
@@ -2033,12 +1903,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
|
|
if (iocb->ki_left == 0)
|
|
|
return 0;
|
|
|
|
|
|
- ret = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- count = ocount;
|
|
|
-
|
|
|
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
|
|
|
|
|
|
appending = file->f_flags & O_APPEND ? 1 : 0;
|
|
@@ -2082,33 +1946,23 @@ relock:
|
|
|
rw_level = -1;
|
|
|
|
|
|
direct_io = 0;
|
|
|
- sync = 1;
|
|
|
goto relock;
|
|
|
}
|
|
|
|
|
|
- if (!sync && ((file->f_flags & O_SYNC) || IS_SYNC(inode)))
|
|
|
- sync = 1;
|
|
|
-
|
|
|
- /*
|
|
|
- * XXX: Is it ok to execute these checks a second time?
|
|
|
- */
|
|
|
- ret = generic_write_checks(file, ppos, &count, S_ISBLK(inode->i_mode));
|
|
|
- if (ret)
|
|
|
- goto out;
|
|
|
-
|
|
|
- /*
|
|
|
- * Set pos so that sync_page_range_nolock() below understands
|
|
|
- * where to start from. We might've moved it around via the
|
|
|
- * calls above. The range we want to actually sync starts from
|
|
|
- * *ppos here.
|
|
|
- *
|
|
|
- */
|
|
|
- pos = *ppos;
|
|
|
-
|
|
|
/* communicate with ocfs2_dio_end_io */
|
|
|
ocfs2_iocb_set_rw_locked(iocb, rw_level);
|
|
|
|
|
|
if (direct_io) {
|
|
|
+ ret = generic_segment_checks(iov, &nr_segs, &ocount,
|
|
|
+ VERIFY_READ);
|
|
|
+ if (ret)
|
|
|
+ goto out_dio;
|
|
|
+
|
|
|
+ ret = generic_write_checks(file, ppos, &count,
|
|
|
+ S_ISBLK(inode->i_mode));
|
|
|
+ if (ret)
|
|
|
+ goto out_dio;
|
|
|
+
|
|
|
written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos,
|
|
|
ppos, count, ocount);
|
|
|
if (written < 0) {
|
|
@@ -2116,14 +1970,8 @@ relock:
|
|
|
goto out_dio;
|
|
|
}
|
|
|
} else {
|
|
|
- written = ocfs2_file_buffered_write(file, ppos, iov, nr_segs,
|
|
|
- count, written);
|
|
|
- if (written < 0) {
|
|
|
- ret = written;
|
|
|
- if (ret != -EFAULT || ret != -ENOSPC)
|
|
|
- mlog_errno(ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ written = generic_file_aio_write_nolock(iocb, iov, nr_segs,
|
|
|
+ *ppos);
|
|
|
}
|
|
|
|
|
|
out_dio:
|
|
@@ -2153,97 +2001,12 @@ out_sems:
|
|
|
if (have_alloc_sem)
|
|
|
up_read(&inode->i_alloc_sem);
|
|
|
|
|
|
- if (written > 0 && sync) {
|
|
|
- ssize_t err;
|
|
|
-
|
|
|
- err = sync_page_range_nolock(inode, file->f_mapping, pos, count);
|
|
|
- if (err < 0)
|
|
|
- written = err;
|
|
|
- }
|
|
|
-
|
|
|
mutex_unlock(&inode->i_mutex);
|
|
|
|
|
|
mlog_exit(ret);
|
|
|
return written ? written : ret;
|
|
|
}
|
|
|
|
|
|
-static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe,
|
|
|
- struct pipe_buffer *buf,
|
|
|
- struct splice_desc *sd)
|
|
|
-{
|
|
|
- int ret, count;
|
|
|
- ssize_t copied = 0;
|
|
|
- struct file *file = sd->u.file;
|
|
|
- unsigned int offset;
|
|
|
- struct page *page = NULL;
|
|
|
- void *fsdata;
|
|
|
- char *src, *dst;
|
|
|
-
|
|
|
- ret = buf->ops->confirm(pipe, buf);
|
|
|
- if (ret)
|
|
|
- goto out;
|
|
|
-
|
|
|
- offset = sd->pos & ~PAGE_CACHE_MASK;
|
|
|
- count = sd->len;
|
|
|
- if (count + offset > PAGE_CACHE_SIZE)
|
|
|
- count = PAGE_CACHE_SIZE - offset;
|
|
|
-
|
|
|
- ret = ocfs2_write_begin(file, file->f_mapping, sd->pos, count, 0,
|
|
|
- &page, &fsdata);
|
|
|
- if (ret) {
|
|
|
- mlog_errno(ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- src = buf->ops->map(pipe, buf, 1);
|
|
|
- dst = kmap_atomic(page, KM_USER1);
|
|
|
- memcpy(dst + offset, src + buf->offset, count);
|
|
|
- kunmap_atomic(dst, KM_USER1);
|
|
|
- buf->ops->unmap(pipe, buf, src);
|
|
|
-
|
|
|
- copied = ocfs2_write_end(file, file->f_mapping, sd->pos, count, count,
|
|
|
- page, fsdata);
|
|
|
- if (copied < 0) {
|
|
|
- mlog_errno(copied);
|
|
|
- ret = copied;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-out:
|
|
|
-
|
|
|
- return copied ? copied : 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, err;
|
|
|
- struct address_space *mapping = out->f_mapping;
|
|
|
- struct inode *inode = mapping->host;
|
|
|
- struct splice_desc sd = {
|
|
|
- .total_len = len,
|
|
|
- .flags = flags,
|
|
|
- .pos = *ppos,
|
|
|
- .u.file = out,
|
|
|
- };
|
|
|
-
|
|
|
- ret = __splice_from_pipe(pipe, &sd, ocfs2_splice_write_actor);
|
|
|
- if (ret > 0) {
|
|
|
- *ppos += ret;
|
|
|
-
|
|
|
- if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
|
|
|
- err = generic_osync_inode(inode, mapping,
|
|
|
- OSYNC_METADATA|OSYNC_DATA);
|
|
|
- if (err)
|
|
|
- ret = err;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
|
|
|
struct file *out,
|
|
|
loff_t *ppos,
|
|
@@ -2273,8 +2036,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
|
|
|
- /* ok, we're done with i_size and alloc work */
|
|
|
- ret = __ocfs2_file_splice_write(pipe, out, ppos, len, flags);
|
|
|
+ ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags);
|
|
|
|
|
|
out_unlock:
|
|
|
ocfs2_rw_unlock(inode, 1);
|