// 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.
*/
/*
* Linux VFS inode operations.
*/
#include <linux/bvec.h>
#include "protocol.h"
#include "orangefs-kernel.h"
#include "orangefs-bufmap.h"
static int orangefs_writepage_locked(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
struct orangefs_write_range *wr = NULL;
struct iov_iter iter;
struct bio_vec bv;
size_t len, wlen;
ssize_t ret;
loff_t off;
set_page_writeback(page);
len = i_size_read(inode);
if (PagePrivate(page)) {
wr = (struct orangefs_write_range *)page_private(page);
WARN_ON(wr->pos >= len);
off = wr->pos;
if (off + wr->len > len)
wlen = len - off;
else
wlen = wr->len;
} else {
WARN_ON(1);
off = page_offset(page);
if (off + PAGE_SIZE > len)
wlen = len - off;
else
wlen = PAGE_SIZE;
}
/* Should've been handled in orangefs_invalidatepage. */
WARN_ON(off == len || off + wlen > len);
bv.bv_page = page;
bv.bv_len = wlen;
bv.bv_offset = off % PAGE_SIZE;
WARN_ON(wlen == 0);
iov_iter_bvec(&iter, WRITE, &bv, 1, wlen);
ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
len, wr, NULL);
if (ret < 0) {
SetPageError(page);
mapping_set_error(page->mapping, ret);
} else {
ret = 0;
}
if (wr) {
kfree(wr);
set_page_private(page, 0);
ClearPagePrivate(page);
put_page(page);
}
return ret;
}
static int orangefs_writepage(struct page *page, struct writeback_control *wbc)
{
int ret;
ret = orangefs_writepage_locked(page, wbc);
unlock_page(page);
end_page_writeback(page);
return ret;
}
struct orangefs_writepages {
loff_t off;
size_t len;
kuid_t uid;
kgid_t gid;
int maxpages;
int npages;
struct page **pages;
struct bio_vec *bv;
};
static int orangefs_writepages_work(struct orangefs_writepages *ow,
struct writeback_control *wbc)
{
struct inode *inode = ow->pages[0]->mapping->host;
struct orangefs_write_range *wrp, wr;