// 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/blkdev.h>
#include <linux/fileattr.h>
#include "protocol.h"
#include "orangefs-kernel.h"
#include "orangefs-bufmap.h"
static int orangefs_writepage_locked(struct folio *folio,
struct writeback_control *wbc)
{
struct inode *inode = folio->mapping->host;
struct orangefs_write_range *wr = NULL;
struct iov_iter iter;
struct bio_vec bv;
size_t wlen;
ssize_t ret;
loff_t len, off;
folio_start_writeback(folio);
len = i_size_read(inode);
if (folio->private) {
wr = folio->private;
off = wr->pos;
if ((off + wr->len > len) && (off <= len))
wlen = len - off;
else
wlen = wr->len;
if (wlen == 0)
wlen = wr->len;
} else {
WARN_ON(1);
off = folio_pos(folio);
wlen = folio_size(folio);
if (wlen > len - off)
wlen = len - off;
}
WARN_ON(wlen == 0);
bvec_set_folio(&bv, folio, wlen, offset_in_folio(folio, off));
iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, wlen);
ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
len, wr, NULL, NULL);
if (ret < 0) {
mapping_set_error(folio->mapping, ret);
} else {
ret = 0;
}
kfree(folio_detach_private(folio));
return ret;
}
struct orangefs_writepages {
loff_t off;
size_t len;
kuid_t uid;
kgid_t gid;
int maxpages;
int nfolios;
struct address_space *mapping;
struct folio **folios;
struct bio_vec *bv;
};
static int orangefs_writepages_work(struct orangefs_writepages *ow,
struct writeback_control *wbc)
{
struct inode *inode = ow->mapping->host;
struct orangefs_write_range *wrp, wr;
struct iov_iter iter;
ssize_t ret;
size_t start;
loff_t len, off;
int i;
len = i_size_read(inode);
start = offset_in_folio(ow->folios[0], ow->off);
for (i = 0; i < ow->nfolios; i++) {
folio_start_writeback(ow->folios[i]);
bvec_set_folio(&ow->bv[i], ow->folios[i],
folio_size(ow->folios[i]) - start, start);
start = 0;
}
iov_iter_bvec(&iter, ITER_SOURCE, ow->bv, ow->nfolios, ow->len);
WARN_ON(ow->off >= len);
if (ow->off + ow->len > len)
ow->len = len - ow->off;
off = ow->off;
wr.uid = ow->uid;
wr.gid = ow->gid;
ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, ow->len,
0, &wr, NULL, NULL);
if (ret < 0)
mapping_set_error(ow->mapping, ret);
else
ret = 0;
for (i = 0; i < ow->nfolios; i++) {
wrp = folio_detach_private(ow->folios[i]);
kfree(wrp);
folio_end_writeback(ow->folios[i]);
folio_unlock(ow->folios[i]);
}
return ret;
}
static int orangefs_writepages_callback(struct folio *folio,
struct writeback_control *wbc, struct orangefs_writepages *ow)
{
struct orangefs_write_range *wr = folio->private