452 lines
11 KiB
C
452 lines
11 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
/*
|
||
|
* linux/fs/nfs/read.c
|
||
|
*
|
||
|
* Block I/O for NFS
|
||
|
*
|
||
|
* Partial copy of Linus' read cache modifications to fs/nfs/file.c
|
||
|
* modified for async RPC by okir@monad.swb.de
|
||
|
*/
|
||
|
|
||
|
#include <linux/time.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/errno.h>
|
||
|
#include <linux/fcntl.h>
|
||
|
#include <linux/stat.h>
|
||
|
#include <linux/mm.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/task_io_accounting_ops.h>
|
||
|
#include <linux/pagemap.h>
|
||
|
#include <linux/sunrpc/clnt.h>
|
||
|
#include <linux/nfs_fs.h>
|
||
|
#include <linux/nfs_page.h>
|
||
|
#include <linux/module.h>
|
||
|
|
||
|
#include "nfs4_fs.h"
|
||
|
#include "internal.h"
|
||
|
#include "iostat.h"
|
||
|
#include "fscache.h"
|
||
|
#include "pnfs.h"
|
||
|
#include "nfstrace.h"
|
||
|
|
||
|
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
|
||
|
|
||
|
static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops;
|
||
|
static const struct nfs_rw_ops nfs_rw_read_ops;
|
||
|
|
||
|
static struct kmem_cache *nfs_rdata_cachep;
|
||
|
|
||
|
static struct nfs_pgio_header *nfs_readhdr_alloc(void)
|
||
|
{
|
||
|
struct nfs_pgio_header *p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
|
||
|
|
||
|
if (p)
|
||
|
p->rw_mode = FMODE_READ;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
static void nfs_readhdr_free(struct nfs_pgio_header *rhdr)
|
||
|
{
|
||
|
kmem_cache_free(nfs_rdata_cachep, rhdr);
|
||
|
}
|
||
|
|
||
|
static int nfs_return_empty_folio(struct folio *folio)
|
||
|
{
|
||
|
folio_zero_segment(folio, 0, folio_size(folio));
|
||
|
folio_mark_uptodate(folio);
|
||
|
folio_unlock(folio);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
|
||
|
struct inode *inode, bool force_mds,
|
||
|
const struct nfs_pgio_completion_ops *compl_ops)
|
||
|
{
|
||
|
struct nfs_server *server = NFS_SERVER(inode);
|
||
|
const struct nfs_pageio_ops *pg_ops = &nfs_pgio_rw_ops;
|
||
|
|
||
|
#ifdef CONFIG_NFS_V4_1
|
||
|
if (server->pnfs_curr_ld && !force_mds)
|
||
|
pg_ops = server->pnfs_curr_ld->pg_read_ops;
|
||
|
#endif
|
||
|
nfs_pageio_init(pgio, inode, pg_ops, compl_ops, &nfs_rw_read_ops,
|
||
|
server->rsize, 0);
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(nfs_pageio_init_read);
|
||
|
|
||
|
static void nfs_pageio_complete_read(struct nfs_pageio_descriptor *pgio)
|
||
|
{
|
||
|
struct nfs_pgio_mirror *pgm;
|
||
|
unsigned long npages;
|
||
|
|
||
|
nfs_pageio_complete(pgio);
|
||
|
|
||
|
/* It doesn't make sense to do mirrored reads! */
|
||
|
WARN_ON_ONCE(pgio->pg_mirror_count != 1);
|
||
|
|
||
|
pgm = &pgio->pg_mirrors[0];
|
||
|
NFS_I(pgio->pg_inode)->read_io += pgm->pg_bytes_written;
|
||
|
npages = (pgm->pg_bytes_written + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
|
nfs_add_stats(pgio->pg_inode, NFSIOS_READPAGES, npages);
|
||
|
}
|
||
|
|
||
|
|
||
|
void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
|
||
|
{
|
||
|
struct nfs_pgio_mirror *mirror;
|
||
|
|
||
|
if (pgio->pg_ops && pgio->pg_ops->pg_cleanup)
|
||
|
pgio->pg_ops->pg_cleanup(pgio);
|
||
|
|
||
|
pgio->pg_ops = &nfs_pgio_rw_ops;
|
||
|
|
||
|
/* read path should never have more than one mirror */
|
||
|
WARN_ON_ONCE(pgio->pg_mirror_count != 1);
|
||
|
|
||
|
mirror = &pgio->pg_mirrors[0];
|
||
|
mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
|
||
|
|
||
|
static void nfs_readpage_release(struct nfs_page *req, int error)
|
||
|
{
|
||
|
struct inode *inode = d_inode(nfs_req_openctx(req)->dentry);
|
||
|
struct folio *folio = nfs_page_to_folio(req);
|
||
|
|
||
|
dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id,
|
||
|
(unsigned long long)NFS_FILEID(inode), req->wb_bytes,
|
||
|
(long long)req_offset(req));
|
||
|
|
||
|
if (nfs_error_is_fatal_on_server(error) && error != -ETIMEDOUT)
|
||
|
folio_set_error(folio);
|
||
|
if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
|
||
|
if (folio_test_uptodate(folio))
|
||
|
nfs_fscache_write_page(inode, &folio->page);
|
||
|
folio_unlock(folio);
|
||
|
}
|
||
|
nfs_release_request(req);
|
||
|
}
|
||
|
|
||
|
struct nfs_readdesc {
|
||
|
struct nfs_pageio_descriptor pgio;
|
||
|
struct nfs_open_context *ctx;
|
||
|
};
|
||
|
|
||
|
static void nfs_page_group_set_uptodate(struct nfs_page *req)
|
||
|
{
|
||
|
if (nfs_page_group_sync_on_bit(req, PG_UPTODATE))
|
||
|
folio_mark_uptodate(nfs_page_to_folio(req));
|
||
|
}
|
||
|
|
||
|
static void nfs_read_completion(struct nfs_pgio_header *hdr)
|
||
|
{
|
||
|
unsigned long bytes = 0;
|
||
|
int error;
|
||
|
|
||
|
if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
|
||
|
goto out;
|
||
|
while (!list_empty(&hdr->pages)) {
|
||
|
struct nfs_page *req = nfs_list_entry(hdr->pages.next);
|
||
|
struct folio *folio = nfs_page_to_folio(req);
|
||
|