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>
This commit is contained in:
Родитель
c453dcfc79
Коммит
85ac799cf9
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* (C) 2001 Clemson University and The University of Chicago
|
* (C) 2001 Clemson University and The University of Chicago
|
||||||
|
* Copyright 2018 Omnibond Systems, L.L.C.
|
||||||
*
|
*
|
||||||
* See COPYING in top-level directory.
|
* 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);
|
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++;
|
orangefs_stats.writes++;
|
||||||
|
return generic_file_write_iter(iocb, iter);
|
||||||
out:
|
|
||||||
|
|
||||||
inode_unlock(file->f_mapping->host);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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 *)file->f_path.dentry->d_name.name :
|
||||||
(char *)"Unknown"));
|
(char *)"Unknown"));
|
||||||
|
|
||||||
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* set the sequential readahead hint */
|
/* set the sequential readahead hint */
|
||||||
vma->vm_flags |= VM_SEQ_READ;
|
vma->vm_flags |= VM_SEQ_READ;
|
||||||
vma->vm_flags &= ~VM_RAND_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,
|
gossip_debug(GOSSIP_INODE_DEBUG,
|
||||||
"flush_racache finished\n");
|
"flush_racache finished\n");
|
||||||
}
|
}
|
||||||
truncate_inode_pages(file_inode(file)->i_mapping,
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -560,6 +504,11 @@ static int orangefs_fsync(struct file *file,
|
||||||
ORANGEFS_I(file_inode(file));
|
ORANGEFS_I(file_inode(file));
|
||||||
struct orangefs_kernel_op_s *new_op = NULL;
|
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);
|
new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
|
||||||
if (!new_op)
|
if (!new_op)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -641,6 +590,11 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int orangefs_flush(struct file *file, fl_owner_t id)
|
||||||
|
{
|
||||||
|
return vfs_fsync(file, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** ORANGEFS implementation of VFS file operations */
|
/** ORANGEFS implementation of VFS file operations */
|
||||||
const struct file_operations orangefs_file_operations = {
|
const struct file_operations orangefs_file_operations = {
|
||||||
.llseek = orangefs_file_llseek,
|
.llseek = orangefs_file_llseek,
|
||||||
|
@ -650,6 +604,7 @@ const struct file_operations orangefs_file_operations = {
|
||||||
.unlocked_ioctl = orangefs_ioctl,
|
.unlocked_ioctl = orangefs_ioctl,
|
||||||
.mmap = orangefs_file_mmap,
|
.mmap = orangefs_file_mmap,
|
||||||
.open = generic_file_open,
|
.open = generic_file_open,
|
||||||
|
.flush = orangefs_flush,
|
||||||
.release = orangefs_file_release,
|
.release = orangefs_file_release,
|
||||||
.fsync = orangefs_fsync,
|
.fsync = orangefs_fsync,
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,50 @@
|
||||||
#include "orangefs-kernel.h"
|
#include "orangefs-kernel.h"
|
||||||
#include "orangefs-bufmap.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)
|
static int orangefs_readpage(struct file *file, struct page *page)
|
||||||
{
|
{
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
|
@ -48,6 +92,15 @@ static int orangefs_readpage(struct file *file, struct page *page)
|
||||||
return ret;
|
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,
|
static void orangefs_invalidatepage(struct page *page,
|
||||||
unsigned int offset,
|
unsigned int offset,
|
||||||
unsigned int length)
|
unsigned int length)
|
||||||
|
@ -77,17 +130,17 @@ static ssize_t orangefs_direct_IO(struct kiocb *iocb,
|
||||||
{
|
{
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
loff_t pos = *(&iocb->ki_pos);
|
loff_t pos = *(&iocb->ki_pos);
|
||||||
/*
|
return do_readv_writev(iov_iter_rw(iter) == WRITE ?
|
||||||
* This cannot happen until write_iter becomes
|
ORANGEFS_IO_WRITE : ORANGEFS_IO_READ, file, &pos, iter);
|
||||||
* generic_file_write_iter.
|
|
||||||
*/
|
|
||||||
BUG_ON(iov_iter_rw(iter) != READ);
|
|
||||||
return do_readv_writev(ORANGEFS_IO_READ, file, &pos, iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ORANGEFS2 implementation of address space operations */
|
/** ORANGEFS2 implementation of address space operations */
|
||||||
static const struct address_space_operations orangefs_address_operations = {
|
static const struct address_space_operations orangefs_address_operations = {
|
||||||
|
.writepage = orangefs_writepage,
|
||||||
.readpage = orangefs_readpage,
|
.readpage = orangefs_readpage,
|
||||||
|
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||||
|
.write_begin = simple_write_begin,
|
||||||
|
.write_end = orangefs_write_end,
|
||||||
.invalidatepage = orangefs_invalidatepage,
|
.invalidatepage = orangefs_invalidatepage,
|
||||||
.releasepage = orangefs_releasepage,
|
.releasepage = orangefs_releasepage,
|
||||||
.direct_IO = orangefs_direct_IO,
|
.direct_IO = orangefs_direct_IO,
|
||||||
|
|
|
@ -247,7 +247,7 @@ again:
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
/* Must have all the attributes in the mask and be within cache time. */
|
/* Must have all the attributes in the mask and be within cache time. */
|
||||||
if ((!flags && time_before(jiffies, orangefs_inode->getattr_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) {
|
if (orangefs_inode->attr_valid) {
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
write_inode_now(inode, 1);
|
write_inode_now(inode, 1);
|
||||||
|
@ -281,12 +281,16 @@ again2:
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
/* Must have all the attributes in the mask and be within cache time. */
|
/* Must have all the attributes in the mask and be within cache time. */
|
||||||
if ((!flags && time_before(jiffies, orangefs_inode->getattr_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) {
|
if (orangefs_inode->attr_valid) {
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
write_inode_now(inode, 1);
|
write_inode_now(inode, 1);
|
||||||
goto again2;
|
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",
|
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: in cache or dirty\n",
|
||||||
__func__);
|
__func__);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче