From 85ac799cf926a589829ebe6274bb5e5a41159743 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Thu, 22 Feb 2018 18:10:43 +0000 Subject: 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 Signed-off-by: Mike Marshall --- fs/orangefs/file.c | 75 +++++++++----------------------------------- fs/orangefs/inode.c | 65 ++++++++++++++++++++++++++++++++++---- fs/orangefs/orangefs-utils.c | 8 +++-- 3 files changed, 80 insertions(+), 68 deletions(-) (limited to 'fs/orangefs') 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; -- cgit v1.2.3-55-g7522