Commit 85ac799c authored by Martin Brandenburg's avatar Martin Brandenburg Committed by Mike Marshall
Browse files

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: default avatarMartin Brandenburg <martin@omnibond.com>
Signed-off-by: default avatarMike Marshall <hubcap@omnibond.com>
parent c453dcfc
Loading
Loading
Loading
Loading
+15 −60
Original line number Diff line number Diff line
// 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,
};
+59 −6
Original line number Diff line number Diff line
@@ -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,
+6 −2
Original line number Diff line number Diff line
@@ -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;