[PATCH 16/18] orangefs: implement write through the page cache

From: Martin Brandenburg
Date: Tue Dec 12 2017 - 13:36:11 EST


From: Martin Brandenburg <martin@xxxxxxxxxxxx>

With this and the previous commit, OrangeFS is capable of writing
through the page cache.

Signed-off-by: Martin Brandenburg <martin@xxxxxxxxxxxx>
---
fs/orangefs/file.c | 132 +++++++++++++++++++++++-----------------------------
fs/orangefs/inode.c | 2 +
fs/orangefs/super.c | 8 ++++
3 files changed, 67 insertions(+), 75 deletions(-)

diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index d80e1e6c1d95..200c72c21b0b 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -397,69 +397,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;
-
- BUG_ON(iocb->private);
-
- 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, 0, 1,
- STATX_SIZE);
- if (rc == -ESTALE)
- rc = -EIO;
- if (rc) {
- gossip_err("%s: orangefs_inode_getattr failed, "
- "rc:%zd:.\n", __func__, rc);
- goto out;
- }
- }
-
- if (file->f_pos > i_size_read(file->f_mapping->host))
- orangefs_i_size_write(file->f_mapping->host, file->f_pos);
-
- 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++;
-
- if (pos > i_size_read(file->f_mapping->host))
- orangefs_i_size_write(file->f_mapping->host, pos);
-
-out:
-
- inode_unlock(file->f_mapping->host);
- return rc;
+ return generic_file_write_iter(iocb, iter);
}

/*
@@ -554,9 +496,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;
@@ -579,9 +518,8 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
file);

/*
- * remove all associated inode pages from the page cache and
- * readahead cache (if any); this forces an expensive refresh of
- * data for the next caller of mmap (or 'get_block' accesses)
+ * remove all associated inode pages from the readahead cache
+ * (if any)
*/
if (file_inode(file) &&
file_inode(file)->i_mapping &&
@@ -594,8 +532,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;
}
@@ -707,6 +643,41 @@ const struct file_operations orangefs_file_operations = {
.fsync = orangefs_fsync,
};

+
+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;
+ loff_t off;
+ size_t len;
+ ssize_t r;
+
+ off = page_offset(page);
+ len = i_size_read(inode);
+ if (off + PAGE_SIZE > len)
+ len = len - off;
+ else
+ len = PAGE_SIZE;
+
+ bv.bv_page = page;
+ bv.bv_len = len;
+ bv.bv_offset = 0;
+ iov_iter_bvec(&iter, ITER_BVEC | WRITE, &bv, 1, len);
+
+ set_page_writeback(page);
+
+ r = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter,
+ len, 0);
+ if (r < 0)
+ mapping_set_error(inode->i_mapping, r);
+
+ end_page_writeback(page);
+ unlock_page(page);
+ return 0;
+}
+
static int orangefs_readpage(struct file *file, struct page *page)
{
int ret;
@@ -752,6 +723,17 @@ 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)
@@ -781,17 +763,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 */
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/inode.c b/fs/orangefs/inode.c
index 2c4f57c5d830..231242a4856e 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -65,6 +65,8 @@ int orangefs_setattr(struct dentry *dentry, struct iattr *iattr)
r = setattr_prepare(dentry, iattr);
if (r)
return r;
+ if (d_is_reg(dentry))
+ filemap_write_and_wait(d_inode(dentry)->i_mapping);
if (iattr->ia_valid & ATTR_SIZE)
if (i_size_read(d_inode(dentry)) != iattr->ia_size)
iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 5c17709862ab..5c1a343ba026 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -315,11 +315,19 @@ static int orangefs_write_inode(struct inode *inode,
return r;
}

+static void orangefs_evict_inode(struct inode *inode)
+{
+ truncate_inode_pages_final(&inode->i_data);
+ clear_inode(inode);
+ filemap_fdatawrite(&inode->i_data);
+}
+
static const struct super_operations orangefs_s_ops = {
.alloc_inode = orangefs_alloc_inode,
.destroy_inode = orangefs_destroy_inode,
.write_inode = orangefs_write_inode,
.drop_inode = generic_drop_inode,
+ .evict_inode = orangefs_evict_inode,
.statfs = orangefs_statfs,
.remount_fs = orangefs_remount_fs,
.show_options = orangefs_show_options,
--
2.15.1