summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Brandenburg <martin@omnibond.com>2018-02-22 18:10:43 +0000
committerMike Marshall <hubcap@omnibond.com>2019-05-03 14:32:38 -0400
commit85ac799cf926a589829ebe6274bb5e5a41159743 (patch)
treedba789ce20ac85065592fa52fda3516a7ea38c7f
parentc453dcfc79815760071bd9a7805d4b809fec05cf (diff)
downloadlinux-85ac799cf926a589829ebe6274bb5e5a41159743.tar.gz
linux-85ac799cf926a589829ebe6274bb5e5a41159743.tar.bz2
linux-85ac799cf926a589829ebe6274bb5e5a41159743.zip
orangefs: implement writepage
Now orangefs_inode_getattr fills from cache if an inode has dirty pages. also if attr_valid and dirty pages and !flags, we spin on inode writeback before returning if pages still dirty after: should it be other way Signed-off-by: Martin Brandenburg <martin@omnibond.com> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
-rw-r--r--fs/orangefs/file.c75
-rw-r--r--fs/orangefs/inode.c65
-rw-r--r--fs/orangefs/orangefs-utils.c8
3 files changed, 80 insertions, 68 deletions
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 934f102ce9e1..d8c97b87bf26 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) 2001 Clemson University and The University of Chicago
+ * Copyright 2018 Omnibond Systems, L.L.C.
*
* See COPYING in top-level directory.
*/
@@ -348,63 +349,11 @@ static ssize_t orangefs_file_read_iter(struct kiocb *iocb,
return generic_file_read_iter(iocb, iter);
}
-static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+static ssize_t orangefs_file_write_iter(struct kiocb *iocb,
+ struct iov_iter *iter)
{
- struct file *file = iocb->ki_filp;
- loff_t pos;
- ssize_t rc;
-
- truncate_inode_pages(file->f_mapping, 0);
-
- gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_write_iter\n");
-
- inode_lock(file->f_mapping->host);
-
- /* Make sure generic_write_checks sees an up to date inode size. */
- if (file->f_flags & O_APPEND) {
- rc = orangefs_inode_getattr(file->f_mapping->host,
- ORANGEFS_GETATTR_SIZE);
- if (rc == -ESTALE)
- rc = -EIO;
- if (rc) {
- gossip_err("%s: orangefs_inode_getattr failed, "
- "rc:%zd:.\n", __func__, rc);
- goto out;
- }
- }
-
- rc = generic_write_checks(iocb, iter);
-
- if (rc <= 0) {
- gossip_err("%s: generic_write_checks failed, rc:%zd:.\n",
- __func__, rc);
- goto out;
- }
-
- /*
- * if we are appending, generic_write_checks would have updated
- * pos to the end of the file, so we will wait till now to set
- * pos...
- */
- pos = iocb->ki_pos;
-
- rc = do_readv_writev(ORANGEFS_IO_WRITE,
- file,
- &pos,
- iter);
- if (rc < 0) {
- gossip_err("%s: do_readv_writev failed, rc:%zd:.\n",
- __func__, rc);
- goto out;
- }
-
- iocb->ki_pos = pos;
orangefs_stats.writes++;
-
-out:
-
- inode_unlock(file->f_mapping->host);
- return rc;
+ return generic_file_write_iter(iocb, iter);
}
/*
@@ -499,9 +448,6 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
(char *)file->f_path.dentry->d_name.name :
(char *)"Unknown"));
- if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
- return -EINVAL;
-
/* set the sequential readahead hint */
vma->vm_flags |= VM_SEQ_READ;
vma->vm_flags &= ~VM_RAND_READ;
@@ -541,8 +487,6 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
gossip_debug(GOSSIP_INODE_DEBUG,
"flush_racache finished\n");
}
- truncate_inode_pages(file_inode(file)->i_mapping,
- 0);
}
return 0;
}
@@ -560,6 +504,11 @@ static int orangefs_fsync(struct file *file,
ORANGEFS_I(file_inode(file));
struct orangefs_kernel_op_s *new_op = NULL;
+ ret = filemap_write_and_wait_range(file_inode(file)->i_mapping,
+ start, end);
+ if (ret < 0)
+ return ret;
+
new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
if (!new_op)
return -ENOMEM;
@@ -641,6 +590,11 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
return rc;
}
+static int orangefs_flush(struct file *file, fl_owner_t id)
+{
+ return vfs_fsync(file, 0);
+}
+
/** ORANGEFS implementation of VFS file operations */
const struct file_operations orangefs_file_operations = {
.llseek = orangefs_file_llseek,
@@ -650,6 +604,7 @@ const struct file_operations orangefs_file_operations = {
.unlocked_ioctl = orangefs_ioctl,
.mmap = orangefs_file_mmap,
.open = generic_file_open,
+ .flush = orangefs_flush,
.release = orangefs_file_release,
.fsync = orangefs_fsync,
};
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 31ee3cb67fe0..3b54974817ea 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -15,6 +15,50 @@
#include "orangefs-kernel.h"
#include "orangefs-bufmap.h"
+static int orangefs_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ struct iov_iter iter;
+ struct bio_vec bv;
+ size_t len, wlen;
+ ssize_t ret;
+ loff_t off;
+
+ set_page_writeback(page);
+
+ off = page_offset(page);
+ len = i_size_read(inode);
+ if (off > len) {
+ /* The file was truncated; there is nothing to write. */
+ unlock_page(page);
+ end_page_writeback(page);
+ return 0;
+ }
+ if (off + PAGE_SIZE > len)
+ wlen = len - off;
+ else
+ wlen = PAGE_SIZE;
+
+ bv.bv_page = page;
+ bv.bv_len = wlen;
+ bv.bv_offset = off % PAGE_SIZE;
+ if (wlen == 0)
+ dump_stack();
+ iov_iter_bvec(&iter, WRITE, &bv, 1, wlen);
+
+ ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
+ len);
+ if (ret < 0) {
+ SetPageError(page);
+ mapping_set_error(page->mapping, ret);
+ } else {
+ ret = 0;
+ }
+ unlock_page(page);
+ end_page_writeback(page);
+ return ret;
+}
+
static int orangefs_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
@@ -48,6 +92,15 @@ static int orangefs_readpage(struct file *file, struct page *page)
return ret;
}
+static int orangefs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata)
+{
+ int r;
+ r = simple_write_end(file, mapping, pos, len, copied, page, fsdata);
+ mark_inode_dirty_sync(file_inode(file));
+ return r;
+}
+
static void orangefs_invalidatepage(struct page *page,
unsigned int offset,
unsigned int length)
@@ -77,17 +130,17 @@ static ssize_t orangefs_direct_IO(struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
loff_t pos = *(&iocb->ki_pos);
- /*
- * This cannot happen until write_iter becomes
- * generic_file_write_iter.
- */
- BUG_ON(iov_iter_rw(iter) != READ);
- return do_readv_writev(ORANGEFS_IO_READ, file, &pos, iter);
+ return do_readv_writev(iov_iter_rw(iter) == WRITE ?
+ ORANGEFS_IO_WRITE : ORANGEFS_IO_READ, file, &pos, iter);
}
/** ORANGEFS2 implementation of address space operations */
static const struct address_space_operations orangefs_address_operations = {
+ .writepage = orangefs_writepage,
.readpage = orangefs_readpage,
+ .set_page_dirty = __set_page_dirty_nobuffers,
+ .write_begin = simple_write_begin,
+ .write_end = orangefs_write_end,
.invalidatepage = orangefs_invalidatepage,
.releasepage = orangefs_releasepage,
.direct_IO = orangefs_direct_IO,
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
index 9221c4a3398e..d6093a468db9 100644
--- a/fs/orangefs/orangefs-utils.c
+++ b/fs/orangefs/orangefs-utils.c
@@ -247,7 +247,7 @@ again:
spin_lock(&inode->i_lock);
/* Must have all the attributes in the mask and be within cache time. */
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
- orangefs_inode->attr_valid) {
+ orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
if (orangefs_inode->attr_valid) {
spin_unlock(&inode->i_lock);
write_inode_now(inode, 1);
@@ -281,12 +281,16 @@ again2:
spin_lock(&inode->i_lock);
/* Must have all the attributes in the mask and be within cache time. */
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
- orangefs_inode->attr_valid) {
+ orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
if (orangefs_inode->attr_valid) {
spin_unlock(&inode->i_lock);
write_inode_now(inode, 1);
goto again2;
}
+ if (inode->i_state & I_DIRTY_PAGES) {
+ ret = 0;
+ goto out_unlock;
+ }
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: in cache or dirty\n",
__func__);
ret = 0;