提交 d1e1cda8 编写于 作者: L Linus Torvalds

Merge tag 'nfs-for-3.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client updates from Trond Myklebust:
 "Highlights include:

   - massive cleanup of the NFS read/write code by Anna and Dros
   - support multiple NFS read/write requests per page in order to deal
     with non-page aligned pNFS striping.  Also cleans up the r/wsize <
     page size code nicely.
   - stable fix for ensuring inode is declared uptodate only after all
     the attributes have been checked.
   - stable fix for a kernel Oops when remounting
   - NFS over RDMA client fixes
   - move the pNFS files layout driver into its own subdirectory"

* tag 'nfs-for-3.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (79 commits)
  NFS: populate ->net in mount data when remounting
  pnfs: fix lockup caused by pnfs_generic_pg_test
  NFSv4.1: Fix typo in dprintk
  NFSv4.1: Comment is now wrong and redundant to code
  NFS: Use raw_write_seqcount_begin/end int nfs4_reclaim_open_state
  xprtrdma: Disconnect on registration failure
  xprtrdma: Remove BUG_ON() call sites
  xprtrdma: Avoid deadlock when credit window is reset
  SUNRPC: Move congestion window constants to header file
  xprtrdma: Reset connection timeout after successful reconnect
  xprtrdma: Use macros for reconnection timeout constants
  xprtrdma: Allocate missing pagelist
  xprtrdma: Remove Tavor MTU setting
  xprtrdma: Ensure ia->ri_id->qp is not NULL when reconnecting
  xprtrdma: Reduce the number of hardway buffer allocations
  xprtrdma: Limit work done by completion handler
  xprtrmda: Reduce calls to ib_poll_cq() in completion handlers
  xprtrmda: Reduce lock contention in completion handlers
  xprtrdma: Split the completion queue
  xprtrdma: Make rpcrdma_ep_destroy() return void
  ...
...@@ -29,8 +29,6 @@ nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o ...@@ -29,8 +29,6 @@ nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o
nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/
nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
obj-$(CONFIG_PNFS_BLOCK) += blocklayout/ obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
...@@ -210,7 +210,7 @@ static void bl_end_io_read(struct bio *bio, int err) ...@@ -210,7 +210,7 @@ static void bl_end_io_read(struct bio *bio, int err)
SetPageUptodate(bvec->bv_page); SetPageUptodate(bvec->bv_page);
if (err) { if (err) {
struct nfs_read_data *rdata = par->data; struct nfs_pgio_data *rdata = par->data;
struct nfs_pgio_header *header = rdata->header; struct nfs_pgio_header *header = rdata->header;
if (!header->pnfs_error) if (!header->pnfs_error)
...@@ -224,17 +224,17 @@ static void bl_end_io_read(struct bio *bio, int err) ...@@ -224,17 +224,17 @@ static void bl_end_io_read(struct bio *bio, int err)
static void bl_read_cleanup(struct work_struct *work) static void bl_read_cleanup(struct work_struct *work)
{ {
struct rpc_task *task; struct rpc_task *task;
struct nfs_read_data *rdata; struct nfs_pgio_data *rdata;
dprintk("%s enter\n", __func__); dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work); task = container_of(work, struct rpc_task, u.tk_work);
rdata = container_of(task, struct nfs_read_data, task); rdata = container_of(task, struct nfs_pgio_data, task);
pnfs_ld_read_done(rdata); pnfs_ld_read_done(rdata);
} }
static void static void
bl_end_par_io_read(void *data, int unused) bl_end_par_io_read(void *data, int unused)
{ {
struct nfs_read_data *rdata = data; struct nfs_pgio_data *rdata = data;
rdata->task.tk_status = rdata->header->pnfs_error; rdata->task.tk_status = rdata->header->pnfs_error;
INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
...@@ -242,7 +242,7 @@ bl_end_par_io_read(void *data, int unused) ...@@ -242,7 +242,7 @@ bl_end_par_io_read(void *data, int unused)
} }
static enum pnfs_try_status static enum pnfs_try_status
bl_read_pagelist(struct nfs_read_data *rdata) bl_read_pagelist(struct nfs_pgio_data *rdata)
{ {
struct nfs_pgio_header *header = rdata->header; struct nfs_pgio_header *header = rdata->header;
int i, hole; int i, hole;
...@@ -390,7 +390,7 @@ static void bl_end_io_write_zero(struct bio *bio, int err) ...@@ -390,7 +390,7 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
} }
if (unlikely(err)) { if (unlikely(err)) {
struct nfs_write_data *data = par->data; struct nfs_pgio_data *data = par->data;
struct nfs_pgio_header *header = data->header; struct nfs_pgio_header *header = data->header;
if (!header->pnfs_error) if (!header->pnfs_error)
...@@ -405,7 +405,7 @@ static void bl_end_io_write(struct bio *bio, int err) ...@@ -405,7 +405,7 @@ static void bl_end_io_write(struct bio *bio, int err)
{ {
struct parallel_io *par = bio->bi_private; struct parallel_io *par = bio->bi_private;
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct nfs_write_data *data = par->data; struct nfs_pgio_data *data = par->data;
struct nfs_pgio_header *header = data->header; struct nfs_pgio_header *header = data->header;
if (!uptodate) { if (!uptodate) {
...@@ -423,10 +423,10 @@ static void bl_end_io_write(struct bio *bio, int err) ...@@ -423,10 +423,10 @@ static void bl_end_io_write(struct bio *bio, int err)
static void bl_write_cleanup(struct work_struct *work) static void bl_write_cleanup(struct work_struct *work)
{ {
struct rpc_task *task; struct rpc_task *task;
struct nfs_write_data *wdata; struct nfs_pgio_data *wdata;
dprintk("%s enter\n", __func__); dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work); task = container_of(work, struct rpc_task, u.tk_work);
wdata = container_of(task, struct nfs_write_data, task); wdata = container_of(task, struct nfs_pgio_data, task);
if (likely(!wdata->header->pnfs_error)) { if (likely(!wdata->header->pnfs_error)) {
/* Marks for LAYOUTCOMMIT */ /* Marks for LAYOUTCOMMIT */
mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg), mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg),
...@@ -438,7 +438,7 @@ static void bl_write_cleanup(struct work_struct *work) ...@@ -438,7 +438,7 @@ static void bl_write_cleanup(struct work_struct *work)
/* Called when last of bios associated with a bl_write_pagelist call finishes */ /* Called when last of bios associated with a bl_write_pagelist call finishes */
static void bl_end_par_io_write(void *data, int num_se) static void bl_end_par_io_write(void *data, int num_se)
{ {
struct nfs_write_data *wdata = data; struct nfs_pgio_data *wdata = data;
if (unlikely(wdata->header->pnfs_error)) { if (unlikely(wdata->header->pnfs_error)) {
bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval, bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval,
...@@ -673,7 +673,7 @@ bl_find_get_zeroing_page(struct inode *inode, pgoff_t index, ...@@ -673,7 +673,7 @@ bl_find_get_zeroing_page(struct inode *inode, pgoff_t index,
} }
static enum pnfs_try_status static enum pnfs_try_status
bl_write_pagelist(struct nfs_write_data *wdata, int sync) bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
{ {
struct nfs_pgio_header *header = wdata->header; struct nfs_pgio_header *header = wdata->header;
int i, ret, npg_zero, pg_index, last = 0; int i, ret, npg_zero, pg_index, last = 0;
...@@ -1189,13 +1189,17 @@ bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) ...@@ -1189,13 +1189,17 @@ bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
pnfs_generic_pg_init_read(pgio, req); pnfs_generic_pg_init_read(pgio, req);
} }
static bool /*
* Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
* of bytes (maximum @req->wb_bytes) that can be coalesced.
*/
static size_t
bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
struct nfs_page *req) struct nfs_page *req)
{ {
if (pgio->pg_dreq != NULL && if (pgio->pg_dreq != NULL &&
!is_aligned_req(req, SECTOR_SIZE)) !is_aligned_req(req, SECTOR_SIZE))
return false; return 0;
return pnfs_generic_pg_test(pgio, prev, req); return pnfs_generic_pg_test(pgio, prev, req);
} }
...@@ -1241,13 +1245,17 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) ...@@ -1241,13 +1245,17 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
} }
} }
static bool /*
* Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
* of bytes (maximum @req->wb_bytes) that can be coalesced.
*/
static size_t
bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
struct nfs_page *req) struct nfs_page *req)
{ {
if (pgio->pg_dreq != NULL && if (pgio->pg_dreq != NULL &&
!is_aligned_req(req, PAGE_CACHE_SIZE)) !is_aligned_req(req, PAGE_CACHE_SIZE))
return false; return 0;
return pnfs_generic_pg_test(pgio, prev, req); return pnfs_generic_pg_test(pgio, prev, req);
} }
......
...@@ -108,6 +108,97 @@ static inline int put_dreq(struct nfs_direct_req *dreq) ...@@ -108,6 +108,97 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
return atomic_dec_and_test(&dreq->io_count); return atomic_dec_and_test(&dreq->io_count);
} }
/*
* nfs_direct_select_verf - select the right verifier
* @dreq - direct request possibly spanning multiple servers
* @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs
* @ds_idx - index of data server in data server list, only valid if ds_clp set
*
* returns the correct verifier to use given the role of the server
*/
static struct nfs_writeverf *
nfs_direct_select_verf(struct nfs_direct_req *dreq,
struct nfs_client *ds_clp,
int ds_idx)
{
struct nfs_writeverf *verfp = &dreq->verf;
#ifdef CONFIG_NFS_V4_1
if (ds_clp) {
/* pNFS is in use, use the DS verf */
if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets)
verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf;
else
WARN_ON_ONCE(1);
}
#endif
return verfp;
}
/*
* nfs_direct_set_hdr_verf - set the write/commit verifier
* @dreq - direct request possibly spanning multiple servers
* @hdr - pageio header to validate against previously seen verfs
*
* Set the server's (MDS or DS) "seen" verifier
*/
static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
struct nfs_pgio_header *hdr)
{
struct nfs_writeverf *verfp;
verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp,
hdr->data->ds_idx);
WARN_ON_ONCE(verfp->committed >= 0);
memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
WARN_ON_ONCE(verfp->committed < 0);
}
/*
* nfs_direct_cmp_hdr_verf - compare verifier for pgio header
* @dreq - direct request possibly spanning multiple servers
* @hdr - pageio header to validate against previously seen verf
*
* set the server's "seen" verf if not initialized.
* returns result of comparison between @hdr->verf and the "seen"
* verf of the server used by @hdr (DS or MDS)
*/
static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
struct nfs_pgio_header *hdr)
{
struct nfs_writeverf *verfp;
verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp,
hdr->data->ds_idx);
if (verfp->committed < 0) {
nfs_direct_set_hdr_verf(dreq, hdr);
return 0;
}
return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
}
#if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4)
/*
* nfs_direct_cmp_commit_data_verf - compare verifier for commit data
* @dreq - direct request possibly spanning multiple servers
* @data - commit data to validate against previously seen verf
*
* returns result of comparison between @data->verf and the verf of
* the server used by @data (DS or MDS)
*/
static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
struct nfs_commit_data *data)
{
struct nfs_writeverf *verfp;
verfp = nfs_direct_select_verf(dreq, data->ds_clp,
data->ds_commit_index);
WARN_ON_ONCE(verfp->committed < 0);
return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
}
#endif
/** /**
* nfs_direct_IO - NFS address space operation for direct I/O * nfs_direct_IO - NFS address space operation for direct I/O
* @rw: direction (read or write) * @rw: direction (read or write)
...@@ -168,6 +259,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) ...@@ -168,6 +259,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
kref_get(&dreq->kref); kref_get(&dreq->kref);
init_completion(&dreq->completion); init_completion(&dreq->completion);
INIT_LIST_HEAD(&dreq->mds_cinfo.list); INIT_LIST_HEAD(&dreq->mds_cinfo.list);
dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */
INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); INIT_WORK(&dreq->work, nfs_direct_write_schedule_work);
spin_lock_init(&dreq->lock); spin_lock_init(&dreq->lock);
...@@ -380,8 +472,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de ...@@ -380,8 +472,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de
struct nfs_page *req; struct nfs_page *req;
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
/* XXX do we need to do the eof zeroing found in async_filler? */ /* XXX do we need to do the eof zeroing found in async_filler? */
req = nfs_create_request(dreq->ctx, dreq->inode, req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
pagevec[i],
pgbase, req_len); pgbase, req_len);
if (IS_ERR(req)) { if (IS_ERR(req)) {
result = PTR_ERR(req); result = PTR_ERR(req);
...@@ -424,7 +515,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -424,7 +515,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
size_t requested_bytes = 0; size_t requested_bytes = 0;
unsigned long seg; unsigned long seg;
NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode, nfs_pageio_init_read(&desc, dreq->inode, false,
&nfs_direct_read_completion_ops); &nfs_direct_read_completion_ops);
get_dreq(dreq); get_dreq(dreq);
desc.pg_dreq = dreq; desc.pg_dreq = dreq;
...@@ -564,7 +655,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) ...@@ -564,7 +655,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
dreq->count = 0; dreq->count = 0;
get_dreq(dreq); get_dreq(dreq);
NFS_PROTO(dreq->inode)->write_pageio_init(&desc, dreq->inode, FLUSH_STABLE, nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false,
&nfs_direct_write_completion_ops); &nfs_direct_write_completion_ops);
desc.pg_dreq = dreq; desc.pg_dreq = dreq;
...@@ -603,7 +694,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) ...@@ -603,7 +694,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
dprintk("NFS: %5u commit failed with error %d.\n", dprintk("NFS: %5u commit failed with error %d.\n",
data->task.tk_pid, status); data->task.tk_pid, status);
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
} else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { } else if (nfs_direct_cmp_commit_data_verf(dreq, data)) {
dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid);
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
} }
...@@ -750,8 +841,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d ...@@ -750,8 +841,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d
struct nfs_page *req; struct nfs_page *req;
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
req = nfs_create_request(dreq->ctx, dreq->inode, req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
pagevec[i],
pgbase, req_len); pgbase, req_len);
if (IS_ERR(req)) { if (IS_ERR(req)) {
result = PTR_ERR(req); result = PTR_ERR(req);
...@@ -813,13 +903,13 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) ...@@ -813,13 +903,13 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
bit = NFS_IOHDR_NEED_RESCHED; bit = NFS_IOHDR_NEED_RESCHED;
else if (dreq->flags == 0) { else if (dreq->flags == 0) {
memcpy(&dreq->verf, hdr->verf, nfs_direct_set_hdr_verf(dreq, hdr);
sizeof(dreq->verf));
bit = NFS_IOHDR_NEED_COMMIT; bit = NFS_IOHDR_NEED_COMMIT;
dreq->flags = NFS_ODIRECT_DO_COMMIT; dreq->flags = NFS_ODIRECT_DO_COMMIT;
} else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) {
if (memcmp(&dreq->verf, hdr->verf, sizeof(dreq->verf))) { if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) {
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; dreq->flags =
NFS_ODIRECT_RESCHED_WRITES;
bit = NFS_IOHDR_NEED_RESCHED; bit = NFS_IOHDR_NEED_RESCHED;
} else } else
bit = NFS_IOHDR_NEED_COMMIT; bit = NFS_IOHDR_NEED_COMMIT;
...@@ -829,6 +919,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) ...@@ -829,6 +919,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
spin_unlock(&dreq->lock); spin_unlock(&dreq->lock);
while (!list_empty(&hdr->pages)) { while (!list_empty(&hdr->pages)) {
bool do_destroy = true;
req = nfs_list_entry(hdr->pages.next); req = nfs_list_entry(hdr->pages.next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
switch (bit) { switch (bit) {
...@@ -836,6 +928,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) ...@@ -836,6 +928,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
case NFS_IOHDR_NEED_COMMIT: case NFS_IOHDR_NEED_COMMIT:
kref_get(&req->wb_kref); kref_get(&req->wb_kref);
nfs_mark_request_commit(req, hdr->lseg, &cinfo); nfs_mark_request_commit(req, hdr->lseg, &cinfo);
do_destroy = false;
} }
nfs_unlock_and_release_request(req); nfs_unlock_and_release_request(req);
} }
...@@ -874,7 +967,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -874,7 +967,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
size_t requested_bytes = 0; size_t requested_bytes = 0;
unsigned long seg; unsigned long seg;
NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE, nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE, false,
&nfs_direct_write_completion_ops); &nfs_direct_write_completion_ops);
desc.pg_dreq = dreq; desc.pg_dreq = dreq;
get_dreq(dreq); get_dreq(dreq);
......
#
# Makefile for the pNFS Files Layout Driver kernel module
#
obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
nfs_layout_nfsv41_files-y := filelayout.o filelayoutdev.o
...@@ -35,11 +35,11 @@ ...@@ -35,11 +35,11 @@
#include <linux/sunrpc/metrics.h> #include <linux/sunrpc/metrics.h>
#include "nfs4session.h" #include "../nfs4session.h"
#include "internal.h" #include "../internal.h"
#include "delegation.h" #include "../delegation.h"
#include "nfs4filelayout.h" #include "filelayout.h"
#include "nfs4trace.h" #include "../nfs4trace.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD #define NFSDBG_FACILITY NFSDBG_PNFS_LD
...@@ -84,7 +84,7 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset) ...@@ -84,7 +84,7 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
BUG(); BUG();
} }
static void filelayout_reset_write(struct nfs_write_data *data) static void filelayout_reset_write(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
struct rpc_task *task = &data->task; struct rpc_task *task = &data->task;
...@@ -105,7 +105,7 @@ static void filelayout_reset_write(struct nfs_write_data *data) ...@@ -105,7 +105,7 @@ static void filelayout_reset_write(struct nfs_write_data *data)
} }
} }
static void filelayout_reset_read(struct nfs_read_data *data) static void filelayout_reset_read(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
struct rpc_task *task = &data->task; struct rpc_task *task = &data->task;
...@@ -243,7 +243,7 @@ static int filelayout_async_handle_error(struct rpc_task *task, ...@@ -243,7 +243,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
/* NFS_PROTO call done callback routines */ /* NFS_PROTO call done callback routines */
static int filelayout_read_done_cb(struct rpc_task *task, static int filelayout_read_done_cb(struct rpc_task *task,
struct nfs_read_data *data) struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
int err; int err;
...@@ -270,7 +270,7 @@ static int filelayout_read_done_cb(struct rpc_task *task, ...@@ -270,7 +270,7 @@ static int filelayout_read_done_cb(struct rpc_task *task,
* rfc5661 is not clear about which credential should be used. * rfc5661 is not clear about which credential should be used.
*/ */
static void static void
filelayout_set_layoutcommit(struct nfs_write_data *wdata) filelayout_set_layoutcommit(struct nfs_pgio_data *wdata)
{ {
struct nfs_pgio_header *hdr = wdata->header; struct nfs_pgio_header *hdr = wdata->header;
...@@ -279,7 +279,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata) ...@@ -279,7 +279,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
return; return;
pnfs_set_layoutcommit(wdata); pnfs_set_layoutcommit(wdata);
dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
} }
...@@ -305,7 +305,7 @@ filelayout_reset_to_mds(struct pnfs_layout_segment *lseg) ...@@ -305,7 +305,7 @@ filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
*/ */
static void filelayout_read_prepare(struct rpc_task *task, void *data) static void filelayout_read_prepare(struct rpc_task *task, void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_pgio_data *rdata = data;
if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) { if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) {
rpc_exit(task, -EIO); rpc_exit(task, -EIO);
...@@ -317,7 +317,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) ...@@ -317,7 +317,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
rpc_exit(task, 0); rpc_exit(task, 0);
return; return;
} }
rdata->read_done_cb = filelayout_read_done_cb; rdata->pgio_done_cb = filelayout_read_done_cb;
if (nfs41_setup_sequence(rdata->ds_clp->cl_session, if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
&rdata->args.seq_args, &rdata->args.seq_args,
...@@ -331,7 +331,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) ...@@ -331,7 +331,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
static void filelayout_read_call_done(struct rpc_task *task, void *data) static void filelayout_read_call_done(struct rpc_task *task, void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_pgio_data *rdata = data;
dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
...@@ -347,14 +347,14 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) ...@@ -347,14 +347,14 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
static void filelayout_read_count_stats(struct rpc_task *task, void *data) static void filelayout_read_count_stats(struct rpc_task *task, void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_pgio_data *rdata = data;
rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics); rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics);
} }
static void filelayout_read_release(void *data) static void filelayout_read_release(void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_pgio_data *rdata = data;
struct pnfs_layout_hdr *lo = rdata->header->lseg->pls_layout; struct pnfs_layout_hdr *lo = rdata->header->lseg->pls_layout;
filelayout_fenceme(lo->plh_inode, lo); filelayout_fenceme(lo->plh_inode, lo);
...@@ -363,7 +363,7 @@ static void filelayout_read_release(void *data) ...@@ -363,7 +363,7 @@ static void filelayout_read_release(void *data)
} }
static int filelayout_write_done_cb(struct rpc_task *task, static int filelayout_write_done_cb(struct rpc_task *task,
struct nfs_write_data *data) struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
int err; int err;
...@@ -419,7 +419,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task, ...@@ -419,7 +419,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
static void filelayout_write_prepare(struct rpc_task *task, void *data) static void filelayout_write_prepare(struct rpc_task *task, void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_pgio_data *wdata = data;
if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) { if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) {
rpc_exit(task, -EIO); rpc_exit(task, -EIO);
...@@ -443,7 +443,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) ...@@ -443,7 +443,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
static void filelayout_write_call_done(struct rpc_task *task, void *data) static void filelayout_write_call_done(struct rpc_task *task, void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_pgio_data *wdata = data;
if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) && if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) &&
task->tk_status == 0) { task->tk_status == 0) {
...@@ -457,14 +457,14 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data) ...@@ -457,14 +457,14 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
static void filelayout_write_count_stats(struct rpc_task *task, void *data) static void filelayout_write_count_stats(struct rpc_task *task, void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_pgio_data *wdata = data;
rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics); rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics);
} }
static void filelayout_write_release(void *data) static void filelayout_write_release(void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_pgio_data *wdata = data;
struct pnfs_layout_hdr *lo = wdata->header->lseg->pls_layout; struct pnfs_layout_hdr *lo = wdata->header->lseg->pls_layout;
filelayout_fenceme(lo->plh_inode, lo); filelayout_fenceme(lo->plh_inode, lo);
...@@ -529,7 +529,7 @@ static const struct rpc_call_ops filelayout_commit_call_ops = { ...@@ -529,7 +529,7 @@ static const struct rpc_call_ops filelayout_commit_call_ops = {
}; };
static enum pnfs_try_status static enum pnfs_try_status
filelayout_read_pagelist(struct nfs_read_data *data) filelayout_read_pagelist(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
struct pnfs_layout_segment *lseg = hdr->lseg; struct pnfs_layout_segment *lseg = hdr->lseg;
...@@ -560,6 +560,7 @@ filelayout_read_pagelist(struct nfs_read_data *data) ...@@ -560,6 +560,7 @@ filelayout_read_pagelist(struct nfs_read_data *data)
/* No multipath support. Use first DS */ /* No multipath support. Use first DS */
atomic_inc(&ds->ds_clp->cl_count); atomic_inc(&ds->ds_clp->cl_count);
data->ds_clp = ds->ds_clp; data->ds_clp = ds->ds_clp;
data->ds_idx = idx;
fh = nfs4_fl_select_ds_fh(lseg, j); fh = nfs4_fl_select_ds_fh(lseg, j);
if (fh) if (fh)
data->args.fh = fh; data->args.fh = fh;
...@@ -568,14 +569,14 @@ filelayout_read_pagelist(struct nfs_read_data *data) ...@@ -568,14 +569,14 @@ filelayout_read_pagelist(struct nfs_read_data *data)
data->mds_offset = offset; data->mds_offset = offset;
/* Perform an asynchronous read to ds */ /* Perform an asynchronous read to ds */
nfs_initiate_read(ds_clnt, data, nfs_initiate_pgio(ds_clnt, data,
&filelayout_read_call_ops, RPC_TASK_SOFTCONN); &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN);
return PNFS_ATTEMPTED; return PNFS_ATTEMPTED;
} }
/* Perform async writes. */ /* Perform async writes. */
static enum pnfs_try_status static enum pnfs_try_status
filelayout_write_pagelist(struct nfs_write_data *data, int sync) filelayout_write_pagelist(struct nfs_pgio_data *data, int sync)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
struct pnfs_layout_segment *lseg = hdr->lseg; struct pnfs_layout_segment *lseg = hdr->lseg;
...@@ -600,20 +601,18 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) ...@@ -600,20 +601,18 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
__func__, hdr->inode->i_ino, sync, (size_t) data->args.count, __func__, hdr->inode->i_ino, sync, (size_t) data->args.count,
offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
data->write_done_cb = filelayout_write_done_cb; data->pgio_done_cb = filelayout_write_done_cb;
atomic_inc(&ds->ds_clp->cl_count); atomic_inc(&ds->ds_clp->cl_count);
data->ds_clp = ds->ds_clp; data->ds_clp = ds->ds_clp;
data->ds_idx = idx;
fh = nfs4_fl_select_ds_fh(lseg, j); fh = nfs4_fl_select_ds_fh(lseg, j);
if (fh) if (fh)
data->args.fh = fh; data->args.fh = fh;
/*
* Get the file offset on the dserver. Set the write offset to
* this offset and save the original offset.
*/
data->args.offset = filelayout_get_dserver_offset(lseg, offset); data->args.offset = filelayout_get_dserver_offset(lseg, offset);
/* Perform an asynchronous write */ /* Perform an asynchronous write */
nfs_initiate_write(ds_clnt, data, nfs_initiate_pgio(ds_clnt, data,
&filelayout_write_call_ops, sync, &filelayout_write_call_ops, sync,
RPC_TASK_SOFTCONN); RPC_TASK_SOFTCONN);
return PNFS_ATTEMPTED; return PNFS_ATTEMPTED;
...@@ -637,7 +636,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, ...@@ -637,7 +636,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
struct nfs4_deviceid_node *d; struct nfs4_deviceid_node *d;
struct nfs4_file_layout_dsaddr *dsaddr; struct nfs4_file_layout_dsaddr *dsaddr;
int status = -EINVAL; int status = -EINVAL;
struct nfs_server *nfss = NFS_SERVER(lo->plh_inode);
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
...@@ -655,7 +653,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, ...@@ -655,7 +653,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
goto out; goto out;
} }
if (!fl->stripe_unit || fl->stripe_unit % PAGE_SIZE) { if (!fl->stripe_unit) {
dprintk("%s Invalid stripe unit (%u)\n", dprintk("%s Invalid stripe unit (%u)\n",
__func__, fl->stripe_unit); __func__, fl->stripe_unit);
goto out; goto out;
...@@ -692,12 +690,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, ...@@ -692,12 +690,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
goto out_put; goto out_put;
} }
if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
dprintk("%s Stripe unit (%u) not aligned with rsize %u "
"wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
nfss->wsize);
}
status = 0; status = 0;
out: out:
dprintk("--> %s returns %d\n", __func__, status); dprintk("--> %s returns %d\n", __func__, status);
...@@ -850,11 +842,15 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, ...@@ -850,11 +842,15 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
{ {
struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
struct pnfs_commit_bucket *buckets; struct pnfs_commit_bucket *buckets;
int size; int size, i;
if (fl->commit_through_mds) if (fl->commit_through_mds)
return 0; return 0;
if (cinfo->ds->nbuckets != 0) {
size = (fl->stripe_type == STRIPE_SPARSE) ?
fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
if (cinfo->ds->nbuckets >= size) {
/* This assumes there is only one IOMODE_RW lseg. What /* This assumes there is only one IOMODE_RW lseg. What
* we really want to do is have a layout_hdr level * we really want to do is have a layout_hdr level
* dictionary of <multipath_list4, fh> keys, each * dictionary of <multipath_list4, fh> keys, each
...@@ -864,30 +860,36 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, ...@@ -864,30 +860,36 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
return 0; return 0;
} }
size = (fl->stripe_type == STRIPE_SPARSE) ?
fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket), buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket),
gfp_flags); gfp_flags);
if (!buckets) if (!buckets)
return -ENOMEM; return -ENOMEM;
else { for (i = 0; i < size; i++) {
int i; INIT_LIST_HEAD(&buckets[i].written);
INIT_LIST_HEAD(&buckets[i].committing);
/* mark direct verifier as unset */
buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW;
}
spin_lock(cinfo->lock); spin_lock(cinfo->lock);
if (cinfo->ds->nbuckets != 0) if (cinfo->ds->nbuckets >= size)
kfree(buckets); goto out;
else { for (i = 0; i < cinfo->ds->nbuckets; i++) {
cinfo->ds->buckets = buckets; list_splice(&cinfo->ds->buckets[i].written,
cinfo->ds->nbuckets = size; &buckets[i].written);
for (i = 0; i < size; i++) { list_splice(&cinfo->ds->buckets[i].committing,
INIT_LIST_HEAD(&buckets[i].written); &buckets[i].committing);
INIT_LIST_HEAD(&buckets[i].committing); buckets[i].direct_verf.committed =
} cinfo->ds->buckets[i].direct_verf.committed;
} buckets[i].wlseg = cinfo->ds->buckets[i].wlseg;
spin_unlock(cinfo->lock); buckets[i].clseg = cinfo->ds->buckets[i].clseg;
return 0;
} }
swap(cinfo->ds->buckets, buckets);
cinfo->ds->nbuckets = size;
out:
spin_unlock(cinfo->lock);
kfree(buckets);
return 0;
} }
static struct pnfs_layout_segment * static struct pnfs_layout_segment *
...@@ -915,47 +917,51 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, ...@@ -915,47 +917,51 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
/* /*
* filelayout_pg_test(). Called by nfs_can_coalesce_requests() * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
* *
* return true : coalesce page * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
* return false : don't coalesce page * of bytes (maximum @req->wb_bytes) that can be coalesced.
*/ */
static bool static size_t
filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
struct nfs_page *req) struct nfs_page *req)
{ {
unsigned int size;
u64 p_stripe, r_stripe; u64 p_stripe, r_stripe;
u32 stripe_unit; u32 stripe_offset;
u64 segment_offset = pgio->pg_lseg->pls_range.offset;
u32 stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
if (!pnfs_generic_pg_test(pgio, prev, req) || /* calls nfs_generic_pg_test */
!nfs_generic_pg_test(pgio, prev, req)) size = pnfs_generic_pg_test(pgio, prev, req);
return false; if (!size)
return 0;
p_stripe = (u64)req_offset(prev); /* see if req and prev are in the same stripe */
r_stripe = (u64)req_offset(req); if (prev) {
stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit; p_stripe = (u64)req_offset(prev) - segment_offset;
r_stripe = (u64)req_offset(req) - segment_offset;
do_div(p_stripe, stripe_unit);
do_div(r_stripe, stripe_unit);
do_div(p_stripe, stripe_unit); if (p_stripe != r_stripe)
do_div(r_stripe, stripe_unit); return 0;
}
return (p_stripe == r_stripe); /* calculate remaining bytes in the current stripe */
div_u64_rem((u64)req_offset(req) - segment_offset,
stripe_unit,
&stripe_offset);
WARN_ON_ONCE(stripe_offset > stripe_unit);
if (stripe_offset >= stripe_unit)
return 0;
return min(stripe_unit - (unsigned int)stripe_offset, size);
} }
static void static void
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req) struct nfs_page *req)
{ {
WARN_ON_ONCE(pgio->pg_lseg != NULL); if (!pgio->pg_lseg)
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
if (req->wb_offset != req->wb_pgbase) {
/*
* Handling unaligned pages is difficult, because have to
* somehow split a req in two in certain cases in the
* pg.test code. Avoid this by just not using pnfs
* in this case.
*/
nfs_pageio_reset_read_mds(pgio);
return;
}
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context, req->wb_context,
0, 0,
NFS4_MAX_UINT64, NFS4_MAX_UINT64,
...@@ -973,11 +979,8 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -973,11 +979,8 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
int status; int status;
WARN_ON_ONCE(pgio->pg_lseg != NULL); if (!pgio->pg_lseg)
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
if (req->wb_offset != req->wb_pgbase)
goto out_mds;
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context, req->wb_context,
0, 0,
NFS4_MAX_UINT64, NFS4_MAX_UINT64,
...@@ -1067,6 +1070,7 @@ filelayout_choose_commit_list(struct nfs_page *req, ...@@ -1067,6 +1070,7 @@ filelayout_choose_commit_list(struct nfs_page *req,
*/ */
j = nfs4_fl_calc_j_index(lseg, req_offset(req)); j = nfs4_fl_calc_j_index(lseg, req_offset(req));
i = select_bucket_index(fl, j); i = select_bucket_index(fl, j);
spin_lock(cinfo->lock);
buckets = cinfo->ds->buckets; buckets = cinfo->ds->buckets;
list = &buckets[i].written; list = &buckets[i].written;
if (list_empty(list)) { if (list_empty(list)) {
...@@ -1080,6 +1084,7 @@ filelayout_choose_commit_list(struct nfs_page *req, ...@@ -1080,6 +1084,7 @@ filelayout_choose_commit_list(struct nfs_page *req,
} }
set_bit(PG_COMMIT_TO_DS, &req->wb_flags); set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
cinfo->ds->nwritten++; cinfo->ds->nwritten++;
spin_unlock(cinfo->lock);
return list; return list;
} }
...@@ -1176,6 +1181,7 @@ transfer_commit_list(struct list_head *src, struct list_head *dst, ...@@ -1176,6 +1181,7 @@ transfer_commit_list(struct list_head *src, struct list_head *dst,
return ret; return ret;
} }
/* Note called with cinfo->lock held. */
static int static int
filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
struct nfs_commit_info *cinfo, struct nfs_commit_info *cinfo,
...@@ -1220,15 +1226,18 @@ static void filelayout_recover_commit_reqs(struct list_head *dst, ...@@ -1220,15 +1226,18 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
struct nfs_commit_info *cinfo) struct nfs_commit_info *cinfo)
{ {
struct pnfs_commit_bucket *b; struct pnfs_commit_bucket *b;
struct pnfs_layout_segment *freeme;
int i; int i;
restart:
spin_lock(cinfo->lock); spin_lock(cinfo->lock);
for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
if (transfer_commit_list(&b->written, dst, cinfo, 0)) { if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
spin_unlock(cinfo->lock); freeme = b->wlseg;
pnfs_put_lseg(b->wlseg);
b->wlseg = NULL; b->wlseg = NULL;
spin_lock(cinfo->lock); spin_unlock(cinfo->lock);
pnfs_put_lseg(freeme);
goto restart;
} }
} }
cinfo->ds->nwritten = 0; cinfo->ds->nwritten = 0;
...@@ -1243,6 +1252,7 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) ...@@ -1243,6 +1252,7 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
struct nfs_commit_data *data; struct nfs_commit_data *data;
int i, j; int i, j;
unsigned int nreq = 0; unsigned int nreq = 0;
struct pnfs_layout_segment *freeme;
fl_cinfo = cinfo->ds; fl_cinfo = cinfo->ds;
bucket = fl_cinfo->buckets; bucket = fl_cinfo->buckets;
...@@ -1253,8 +1263,10 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) ...@@ -1253,8 +1263,10 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
if (!data) if (!data)
break; break;
data->ds_commit_index = i; data->ds_commit_index = i;
spin_lock(cinfo->lock);
data->lseg = bucket->clseg; data->lseg = bucket->clseg;
bucket->clseg = NULL; bucket->clseg = NULL;
spin_unlock(cinfo->lock);
list_add(&data->pages, list); list_add(&data->pages, list);
nreq++; nreq++;
} }
...@@ -1264,8 +1276,11 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) ...@@ -1264,8 +1276,11 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
if (list_empty(&bucket->committing)) if (list_empty(&bucket->committing))
continue; continue;
nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo);
pnfs_put_lseg(bucket->clseg); spin_lock(cinfo->lock);
freeme = bucket->clseg;
bucket->clseg = NULL; bucket->clseg = NULL;
spin_unlock(cinfo->lock);
pnfs_put_lseg(freeme);
} }
/* Caller will clean up entries put on list */ /* Caller will clean up entries put on list */
return nreq; return nreq;
...@@ -1330,7 +1345,7 @@ filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) ...@@ -1330,7 +1345,7 @@ filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
struct nfs4_filelayout *flo; struct nfs4_filelayout *flo;
flo = kzalloc(sizeof(*flo), gfp_flags); flo = kzalloc(sizeof(*flo), gfp_flags);
return &flo->generic_hdr; return flo != NULL ? &flo->generic_hdr : NULL;
} }
static void static void
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#ifndef FS_NFS_NFS4FILELAYOUT_H #ifndef FS_NFS_NFS4FILELAYOUT_H
#define FS_NFS_NFS4FILELAYOUT_H #define FS_NFS_NFS4FILELAYOUT_H
#include "pnfs.h" #include "../pnfs.h"
/* /*
* Default data server connection timeout and retrans vaules. * Default data server connection timeout and retrans vaules.
......
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sunrpc/addr.h> #include <linux/sunrpc/addr.h>
#include "internal.h" #include "../internal.h"
#include "nfs4session.h" #include "../nfs4session.h"
#include "nfs4filelayout.h" #include "filelayout.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD #define NFSDBG_FACILITY NFSDBG_PNFS_LD
......
...@@ -120,7 +120,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, ...@@ -120,7 +120,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
security_d_instantiate(ret, inode); security_d_instantiate(ret, inode);
spin_lock(&ret->d_lock); spin_lock(&ret->d_lock);
if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { if (IS_ROOT(ret) && !ret->d_fsdata &&
!(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
ret->d_fsdata = name; ret->d_fsdata = name;
name = NULL; name = NULL;
} }
......
...@@ -1575,18 +1575,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1575,18 +1575,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
} }
} else if (server->caps & NFS_CAP_CHANGE_ATTR) } else if (server->caps & NFS_CAP_CHANGE_ATTR)
invalid |= save_cache_validity; nfsi->cache_validity |= save_cache_validity;
if (fattr->valid & NFS_ATTR_FATTR_MTIME) { if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
} else if (server->caps & NFS_CAP_MTIME) } else if (server->caps & NFS_CAP_MTIME)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
if (fattr->valid & NFS_ATTR_FATTR_CTIME) { if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
} else if (server->caps & NFS_CAP_CTIME) } else if (server->caps & NFS_CAP_CTIME)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
/* Check if our cached file size is stale */ /* Check if our cached file size is stale */
...@@ -1608,7 +1610,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1608,7 +1610,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
(long long)new_isize); (long long)new_isize);
} }
} else } else
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_PAGECACHE
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
...@@ -1616,7 +1619,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1616,7 +1619,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (fattr->valid & NFS_ATTR_FATTR_ATIME) if (fattr->valid & NFS_ATTR_FATTR_ATIME)
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
else if (server->caps & NFS_CAP_ATIME) else if (server->caps & NFS_CAP_ATIME)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATIME
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
if (fattr->valid & NFS_ATTR_FATTR_MODE) { if (fattr->valid & NFS_ATTR_FATTR_MODE) {
...@@ -1627,7 +1631,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1627,7 +1631,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
} }
} else if (server->caps & NFS_CAP_MODE) } else if (server->caps & NFS_CAP_MODE)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
...@@ -1638,7 +1643,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1638,7 +1643,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_uid = fattr->uid; inode->i_uid = fattr->uid;
} }
} else if (server->caps & NFS_CAP_OWNER) } else if (server->caps & NFS_CAP_OWNER)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
...@@ -1649,7 +1655,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1649,7 +1655,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_gid = fattr->gid; inode->i_gid = fattr->gid;
} }
} else if (server->caps & NFS_CAP_OWNER_GROUP) } else if (server->caps & NFS_CAP_OWNER_GROUP)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
...@@ -1662,7 +1669,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1662,7 +1669,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
set_nlink(inode, fattr->nlink); set_nlink(inode, fattr->nlink);
} }
} else if (server->caps & NFS_CAP_NLINK) } else if (server->caps & NFS_CAP_NLINK)
invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
......
...@@ -231,13 +231,20 @@ extern void nfs_destroy_writepagecache(void); ...@@ -231,13 +231,20 @@ extern void nfs_destroy_writepagecache(void);
extern int __init nfs_init_directcache(void); extern int __init nfs_init_directcache(void);
extern void nfs_destroy_directcache(void); extern void nfs_destroy_directcache(void);
extern bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount);
extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr, struct nfs_pgio_header *hdr,
void (*release)(struct nfs_pgio_header *hdr)); void (*release)(struct nfs_pgio_header *hdr));
void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos);
int nfs_iocounter_wait(struct nfs_io_counter *c); int nfs_iocounter_wait(struct nfs_io_counter *c);
extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
struct nfs_rw_header *nfs_rw_header_alloc(const struct nfs_rw_ops *);
void nfs_rw_header_free(struct nfs_pgio_header *);
void nfs_pgio_data_release(struct nfs_pgio_data *);
int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_data *,
const struct rpc_call_ops *, int, int);
static inline void nfs_iocounter_init(struct nfs_io_counter *c) static inline void nfs_iocounter_init(struct nfs_io_counter *c)
{ {
c->flags = 0; c->flags = 0;
...@@ -395,19 +402,11 @@ extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool ...@@ -395,19 +402,11 @@ extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool
struct nfs_pgio_completion_ops; struct nfs_pgio_completion_ops;
/* read.c */ /* read.c */
extern struct nfs_read_header *nfs_readhdr_alloc(void);
extern void nfs_readhdr_free(struct nfs_pgio_header *hdr);
extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
struct inode *inode, struct inode *inode, bool force_mds,
const struct nfs_pgio_completion_ops *compl_ops); const struct nfs_pgio_completion_ops *compl_ops);
extern int nfs_initiate_read(struct rpc_clnt *clnt,
struct nfs_read_data *data,
const struct rpc_call_ops *call_ops, int flags);
extern void nfs_read_prepare(struct rpc_task *task, void *calldata); extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr);
extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_readdata_release(struct nfs_read_data *rdata);
/* super.c */ /* super.c */
void nfs_clone_super(struct super_block *, struct nfs_mount_info *); void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
...@@ -422,19 +421,10 @@ int nfs_remount(struct super_block *sb, int *flags, char *raw_data); ...@@ -422,19 +421,10 @@ int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
/* write.c */ /* write.c */
extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
struct inode *inode, int ioflags, struct inode *inode, int ioflags, bool force_mds,
const struct nfs_pgio_completion_ops *compl_ops); const struct nfs_pgio_completion_ops *compl_ops);
extern struct nfs_write_header *nfs_writehdr_alloc(void);
extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr);
extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_writedata_release(struct nfs_write_data *wdata);
extern void nfs_commit_free(struct nfs_commit_data *p); extern void nfs_commit_free(struct nfs_commit_data *p);
extern int nfs_initiate_write(struct rpc_clnt *clnt,
struct nfs_write_data *data,
const struct rpc_call_ops *call_ops,
int how, int flags);
extern void nfs_write_prepare(struct rpc_task *task, void *calldata); extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
extern void nfs_commit_prepare(struct rpc_task *task, void *calldata); extern void nfs_commit_prepare(struct rpc_task *task, void *calldata);
extern int nfs_initiate_commit(struct rpc_clnt *clnt, extern int nfs_initiate_commit(struct rpc_clnt *clnt,
...@@ -447,6 +437,7 @@ extern void nfs_init_commit(struct nfs_commit_data *data, ...@@ -447,6 +437,7 @@ extern void nfs_init_commit(struct nfs_commit_data *data,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo);
int nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
struct nfs_commit_info *cinfo, int max); struct nfs_commit_info *cinfo, int max);
unsigned long nfs_reqs_to_commit(struct nfs_commit_info *);
int nfs_scan_commit(struct inode *inode, struct list_head *dst, int nfs_scan_commit(struct inode *inode, struct list_head *dst,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo);
void nfs_mark_request_commit(struct nfs_page *req, void nfs_mark_request_commit(struct nfs_page *req,
...@@ -492,7 +483,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode) ...@@ -492,7 +483,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode)
extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq);
/* nfs4proc.c */ /* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_read_data *); extern void __nfs4_read_done_cb(struct nfs_pgio_data *);
extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms, const struct rpc_timeout *timeparms,
const char *ip_addr); const char *ip_addr);
......
...@@ -103,7 +103,7 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) ...@@ -103,7 +103,7 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
/* /*
* typedef opaque nfsdata<>; * typedef opaque nfsdata<>;
*/ */
static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
{ {
u32 recvd, count; u32 recvd, count;
__be32 *p; __be32 *p;
...@@ -613,7 +613,7 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, ...@@ -613,7 +613,7 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
* }; * };
*/ */
static void encode_readargs(struct xdr_stream *xdr, static void encode_readargs(struct xdr_stream *xdr,
const struct nfs_readargs *args) const struct nfs_pgio_args *args)
{ {
u32 offset = args->offset; u32 offset = args->offset;
u32 count = args->count; u32 count = args->count;
...@@ -629,7 +629,7 @@ static void encode_readargs(struct xdr_stream *xdr, ...@@ -629,7 +629,7 @@ static void encode_readargs(struct xdr_stream *xdr,
static void nfs2_xdr_enc_readargs(struct rpc_rqst *req, static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs_readargs *args) const struct nfs_pgio_args *args)
{ {
encode_readargs(xdr, args); encode_readargs(xdr, args);
prepare_reply_buffer(req, args->pages, args->pgbase, prepare_reply_buffer(req, args->pages, args->pgbase,
...@@ -649,7 +649,7 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req, ...@@ -649,7 +649,7 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
* }; * };
*/ */
static void encode_writeargs(struct xdr_stream *xdr, static void encode_writeargs(struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_pgio_args *args)
{ {
u32 offset = args->offset; u32 offset = args->offset;
u32 count = args->count; u32 count = args->count;
...@@ -669,7 +669,7 @@ static void encode_writeargs(struct xdr_stream *xdr, ...@@ -669,7 +669,7 @@ static void encode_writeargs(struct xdr_stream *xdr,
static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req, static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_pgio_args *args)
{ {
encode_writeargs(xdr, args); encode_writeargs(xdr, args);
xdr->buf->flags |= XDRBUF_WRITE; xdr->buf->flags |= XDRBUF_WRITE;
...@@ -857,7 +857,7 @@ static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, ...@@ -857,7 +857,7 @@ static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
* }; * };
*/ */
static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_readres *result) struct nfs_pgio_res *result)
{ {
enum nfs_stat status; enum nfs_stat status;
int error; int error;
...@@ -878,7 +878,7 @@ static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -878,7 +878,7 @@ static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
} }
static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_writeres *result) struct nfs_pgio_res *result)
{ {
/* All NFSv2 writes are "file sync" writes */ /* All NFSv2 writes are "file sync" writes */
result->verf->committed = NFS_FILE_SYNC; result->verf->committed = NFS_FILE_SYNC;
......
...@@ -795,7 +795,7 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -795,7 +795,7 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return status; return status;
} }
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
...@@ -807,18 +807,18 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) ...@@ -807,18 +807,18 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
return 0; return 0;
} }
static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) static void nfs3_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
} }
static int nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
rpc_call_start(task); rpc_call_start(task);
return 0; return 0;
} }
static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
...@@ -829,17 +829,11 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -829,17 +829,11 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
return 0; return 0;
} }
static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) static void nfs3_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
} }
static int nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
{
rpc_call_start(task);
return 0;
}
static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
{ {
rpc_call_start(task); rpc_call_start(task);
...@@ -946,13 +940,10 @@ const struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -946,13 +940,10 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.fsinfo = nfs3_proc_fsinfo, .fsinfo = nfs3_proc_fsinfo,
.pathconf = nfs3_proc_pathconf, .pathconf = nfs3_proc_pathconf,
.decode_dirent = nfs3_decode_dirent, .decode_dirent = nfs3_decode_dirent,
.pgio_rpc_prepare = nfs3_proc_pgio_rpc_prepare,
.read_setup = nfs3_proc_read_setup, .read_setup = nfs3_proc_read_setup,
.read_pageio_init = nfs_pageio_init_read,
.read_rpc_prepare = nfs3_proc_read_rpc_prepare,
.read_done = nfs3_read_done, .read_done = nfs3_read_done,
.write_setup = nfs3_proc_write_setup, .write_setup = nfs3_proc_write_setup,
.write_pageio_init = nfs_pageio_init_write,
.write_rpc_prepare = nfs3_proc_write_rpc_prepare,
.write_done = nfs3_write_done, .write_done = nfs3_write_done,
.commit_setup = nfs3_proc_commit_setup, .commit_setup = nfs3_proc_commit_setup,
.commit_rpc_prepare = nfs3_proc_commit_rpc_prepare, .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare,
......
...@@ -953,7 +953,7 @@ static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, ...@@ -953,7 +953,7 @@ static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
* }; * };
*/ */
static void encode_read3args(struct xdr_stream *xdr, static void encode_read3args(struct xdr_stream *xdr,
const struct nfs_readargs *args) const struct nfs_pgio_args *args)
{ {
__be32 *p; __be32 *p;
...@@ -966,7 +966,7 @@ static void encode_read3args(struct xdr_stream *xdr, ...@@ -966,7 +966,7 @@ static void encode_read3args(struct xdr_stream *xdr,
static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs_readargs *args) const struct nfs_pgio_args *args)
{ {
encode_read3args(xdr, args); encode_read3args(xdr, args);
prepare_reply_buffer(req, args->pages, args->pgbase, prepare_reply_buffer(req, args->pages, args->pgbase,
...@@ -992,7 +992,7 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, ...@@ -992,7 +992,7 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
* }; * };
*/ */
static void encode_write3args(struct xdr_stream *xdr, static void encode_write3args(struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_pgio_args *args)
{ {
__be32 *p; __be32 *p;
...@@ -1008,7 +1008,7 @@ static void encode_write3args(struct xdr_stream *xdr, ...@@ -1008,7 +1008,7 @@ static void encode_write3args(struct xdr_stream *xdr,
static void nfs3_xdr_enc_write3args(struct rpc_rqst *req, static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_pgio_args *args)
{ {
encode_write3args(xdr, args); encode_write3args(xdr, args);
xdr->buf->flags |= XDRBUF_WRITE; xdr->buf->flags |= XDRBUF_WRITE;
...@@ -1589,7 +1589,7 @@ static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, ...@@ -1589,7 +1589,7 @@ static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
* }; * };
*/ */
static int decode_read3resok(struct xdr_stream *xdr, static int decode_read3resok(struct xdr_stream *xdr,
struct nfs_readres *result) struct nfs_pgio_res *result)
{ {
u32 eof, count, ocount, recvd; u32 eof, count, ocount, recvd;
__be32 *p; __be32 *p;
...@@ -1625,7 +1625,7 @@ static int decode_read3resok(struct xdr_stream *xdr, ...@@ -1625,7 +1625,7 @@ static int decode_read3resok(struct xdr_stream *xdr,
} }
static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_readres *result) struct nfs_pgio_res *result)
{ {
enum nfs_stat status; enum nfs_stat status;
int error; int error;
...@@ -1673,7 +1673,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1673,7 +1673,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
* }; * };
*/ */
static int decode_write3resok(struct xdr_stream *xdr, static int decode_write3resok(struct xdr_stream *xdr,
struct nfs_writeres *result) struct nfs_pgio_res *result)
{ {
__be32 *p; __be32 *p;
...@@ -1697,7 +1697,7 @@ static int decode_write3resok(struct xdr_stream *xdr, ...@@ -1697,7 +1697,7 @@ static int decode_write3resok(struct xdr_stream *xdr,
} }
static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_writeres *result) struct nfs_pgio_res *result)
{ {
enum nfs_stat status; enum nfs_stat status;
int error; int error;
......
...@@ -337,7 +337,7 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode, ...@@ -337,7 +337,7 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
*/ */
static inline void static inline void
nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
struct rpc_message *msg, struct nfs_write_data *wdata) struct rpc_message *msg, struct nfs_pgio_data *wdata)
{ {
if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) && if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) &&
!test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags)) !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags))
...@@ -369,7 +369,7 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags, ...@@ -369,7 +369,7 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags,
static inline void static inline void
nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
struct rpc_message *msg, struct nfs_write_data *wdata) struct rpc_message *msg, struct nfs_pgio_data *wdata)
{ {
} }
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
......
...@@ -100,8 +100,7 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -100,8 +100,7 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
break; break;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
ret = nfs_file_fsync_commit(file, start, end, datasync); ret = nfs_file_fsync_commit(file, start, end, datasync);
if (!ret && !datasync) if (!ret)
/* application has asked for meta-data sync */
ret = pnfs_layoutcommit_inode(inode, true); ret = pnfs_layoutcommit_inode(inode, true);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
/* /*
......
...@@ -2027,7 +2027,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -2027,7 +2027,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return status; return status;
} }
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
_nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label); nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
return 0; return 0;
} }
...@@ -4033,12 +4033,12 @@ static bool nfs4_error_stateid_expired(int err) ...@@ -4033,12 +4033,12 @@ static bool nfs4_error_stateid_expired(int err)
return false; return false;
} }
void __nfs4_read_done_cb(struct nfs_read_data *data) void __nfs4_read_done_cb(struct nfs_pgio_data *data)
{ {
nfs_invalidate_atime(data->header->inode); nfs_invalidate_atime(data->header->inode);
} }
static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct nfs_server *server = NFS_SERVER(data->header->inode); struct nfs_server *server = NFS_SERVER(data->header->inode);
...@@ -4055,7 +4055,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) ...@@ -4055,7 +4055,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
} }
static bool nfs4_read_stateid_changed(struct rpc_task *task, static bool nfs4_read_stateid_changed(struct rpc_task *task,
struct nfs_readargs *args) struct nfs_pgio_args *args)
{ {
if (!nfs4_error_stateid_expired(task->tk_status) || if (!nfs4_error_stateid_expired(task->tk_status) ||
...@@ -4068,7 +4068,7 @@ static bool nfs4_read_stateid_changed(struct rpc_task *task, ...@@ -4068,7 +4068,7 @@ static bool nfs4_read_stateid_changed(struct rpc_task *task,
return true; return true;
} }
static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
...@@ -4077,19 +4077,19 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) ...@@ -4077,19 +4077,19 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
return -EAGAIN; return -EAGAIN;
if (nfs4_read_stateid_changed(task, &data->args)) if (nfs4_read_stateid_changed(task, &data->args))
return -EAGAIN; return -EAGAIN;
return data->read_done_cb ? data->read_done_cb(task, data) : return data->pgio_done_cb ? data->pgio_done_cb(task, data) :
nfs4_read_done_cb(task, data); nfs4_read_done_cb(task, data);
} }
static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) static void nfs4_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
data->timestamp = jiffies; data->timestamp = jiffies;
data->read_done_cb = nfs4_read_done_cb; data->pgio_done_cb = nfs4_read_done_cb;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
} }
static int nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args, &data->args.seq_args,
...@@ -4097,14 +4097,14 @@ static int nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_dat ...@@ -4097,14 +4097,14 @@ static int nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_dat
task)) task))
return 0; return 0;
if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context, if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
data->args.lock_context, FMODE_READ) == -EIO) data->args.lock_context, data->header->rw_ops->rw_mode) == -EIO)
return -EIO; return -EIO;
if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags))) if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
return -EIO; return -EIO;
return 0; return 0;
} }
static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
...@@ -4121,7 +4121,7 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data ...@@ -4121,7 +4121,7 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data
} }
static bool nfs4_write_stateid_changed(struct rpc_task *task, static bool nfs4_write_stateid_changed(struct rpc_task *task,
struct nfs_writeargs *args) struct nfs_pgio_args *args)
{ {
if (!nfs4_error_stateid_expired(task->tk_status) || if (!nfs4_error_stateid_expired(task->tk_status) ||
...@@ -4134,18 +4134,18 @@ static bool nfs4_write_stateid_changed(struct rpc_task *task, ...@@ -4134,18 +4134,18 @@ static bool nfs4_write_stateid_changed(struct rpc_task *task,
return true; return true;
} }
static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
if (!nfs4_sequence_done(task, &data->res.seq_res)) if (!nfs4_sequence_done(task, &data->res.seq_res))
return -EAGAIN; return -EAGAIN;
if (nfs4_write_stateid_changed(task, &data->args)) if (nfs4_write_stateid_changed(task, &data->args))
return -EAGAIN; return -EAGAIN;
return data->write_done_cb ? data->write_done_cb(task, data) : return data->pgio_done_cb ? data->pgio_done_cb(task, data) :
nfs4_write_done_cb(task, data); nfs4_write_done_cb(task, data);
} }
static static
bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data) bool nfs4_write_need_cache_consistency_data(const struct nfs_pgio_data *data)
{ {
const struct nfs_pgio_header *hdr = data->header; const struct nfs_pgio_header *hdr = data->header;
...@@ -4158,7 +4158,7 @@ bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data) ...@@ -4158,7 +4158,7 @@ bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data)
return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0; return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
} }
static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) static void nfs4_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
struct nfs_server *server = NFS_SERVER(data->header->inode); struct nfs_server *server = NFS_SERVER(data->header->inode);
...@@ -4168,8 +4168,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag ...@@ -4168,8 +4168,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
} else } else
data->args.bitmask = server->cache_consistency_bitmask; data->args.bitmask = server->cache_consistency_bitmask;
if (!data->write_done_cb) if (!data->pgio_done_cb)
data->write_done_cb = nfs4_write_done_cb; data->pgio_done_cb = nfs4_write_done_cb;
data->res.server = server; data->res.server = server;
data->timestamp = jiffies; data->timestamp = jiffies;
...@@ -4177,21 +4177,6 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag ...@@ -4177,21 +4177,6 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
} }
static int nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
{
if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args,
&data->res.seq_res,
task))
return 0;
if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
data->args.lock_context, FMODE_WRITE) == -EIO)
return -EIO;
if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
return -EIO;
return 0;
}
static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
{ {
nfs4_setup_sequence(NFS_SERVER(data->inode), nfs4_setup_sequence(NFS_SERVER(data->inode),
...@@ -8432,13 +8417,10 @@ const struct nfs_rpc_ops nfs_v4_clientops = { ...@@ -8432,13 +8417,10 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.pathconf = nfs4_proc_pathconf, .pathconf = nfs4_proc_pathconf,
.set_capabilities = nfs4_server_capabilities, .set_capabilities = nfs4_server_capabilities,
.decode_dirent = nfs4_decode_dirent, .decode_dirent = nfs4_decode_dirent,
.pgio_rpc_prepare = nfs4_proc_pgio_rpc_prepare,
.read_setup = nfs4_proc_read_setup, .read_setup = nfs4_proc_read_setup,
.read_pageio_init = pnfs_pageio_init_read,
.read_rpc_prepare = nfs4_proc_read_rpc_prepare,
.read_done = nfs4_read_done, .read_done = nfs4_read_done,
.write_setup = nfs4_proc_write_setup, .write_setup = nfs4_proc_write_setup,
.write_pageio_init = pnfs_pageio_init_write,
.write_rpc_prepare = nfs4_proc_write_rpc_prepare,
.write_done = nfs4_write_done, .write_done = nfs4_write_done,
.commit_setup = nfs4_proc_commit_setup, .commit_setup = nfs4_proc_commit_setup,
.commit_rpc_prepare = nfs4_proc_commit_rpc_prepare, .commit_rpc_prepare = nfs4_proc_commit_rpc_prepare,
......
...@@ -1456,7 +1456,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1456,7 +1456,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
* server that doesn't support a grace period. * server that doesn't support a grace period.
*/ */
spin_lock(&sp->so_lock); spin_lock(&sp->so_lock);
write_seqcount_begin(&sp->so_reclaim_seqcount); raw_write_seqcount_begin(&sp->so_reclaim_seqcount);
restart: restart:
list_for_each_entry(state, &sp->so_states, open_states) { list_for_each_entry(state, &sp->so_states, open_states) {
if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
...@@ -1519,13 +1519,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1519,13 +1519,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
spin_lock(&sp->so_lock); spin_lock(&sp->so_lock);
goto restart; goto restart;
} }
write_seqcount_end(&sp->so_reclaim_seqcount); raw_write_seqcount_end(&sp->so_reclaim_seqcount);
spin_unlock(&sp->so_lock); spin_unlock(&sp->so_lock);
return 0; return 0;
out_err: out_err:
nfs4_put_open_state(state); nfs4_put_open_state(state);
spin_lock(&sp->so_lock); spin_lock(&sp->so_lock);
write_seqcount_end(&sp->so_reclaim_seqcount); raw_write_seqcount_end(&sp->so_reclaim_seqcount);
spin_unlock(&sp->so_lock); spin_unlock(&sp->so_lock);
return status; return status;
} }
......
...@@ -932,7 +932,7 @@ DEFINE_NFS4_IDMAP_EVENT(nfs4_map_gid_to_group); ...@@ -932,7 +932,7 @@ DEFINE_NFS4_IDMAP_EVENT(nfs4_map_gid_to_group);
DECLARE_EVENT_CLASS(nfs4_read_event, DECLARE_EVENT_CLASS(nfs4_read_event,
TP_PROTO( TP_PROTO(
const struct nfs_read_data *data, const struct nfs_pgio_data *data,
int error int error
), ),
...@@ -972,7 +972,7 @@ DECLARE_EVENT_CLASS(nfs4_read_event, ...@@ -972,7 +972,7 @@ DECLARE_EVENT_CLASS(nfs4_read_event,
#define DEFINE_NFS4_READ_EVENT(name) \ #define DEFINE_NFS4_READ_EVENT(name) \
DEFINE_EVENT(nfs4_read_event, name, \ DEFINE_EVENT(nfs4_read_event, name, \
TP_PROTO( \ TP_PROTO( \
const struct nfs_read_data *data, \ const struct nfs_pgio_data *data, \
int error \ int error \
), \ ), \
TP_ARGS(data, error)) TP_ARGS(data, error))
...@@ -983,7 +983,7 @@ DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); ...@@ -983,7 +983,7 @@ DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read);
DECLARE_EVENT_CLASS(nfs4_write_event, DECLARE_EVENT_CLASS(nfs4_write_event,
TP_PROTO( TP_PROTO(
const struct nfs_write_data *data, const struct nfs_pgio_data *data,
int error int error
), ),
...@@ -1024,7 +1024,7 @@ DECLARE_EVENT_CLASS(nfs4_write_event, ...@@ -1024,7 +1024,7 @@ DECLARE_EVENT_CLASS(nfs4_write_event,
#define DEFINE_NFS4_WRITE_EVENT(name) \ #define DEFINE_NFS4_WRITE_EVENT(name) \
DEFINE_EVENT(nfs4_write_event, name, \ DEFINE_EVENT(nfs4_write_event, name, \
TP_PROTO( \ TP_PROTO( \
const struct nfs_write_data *data, \ const struct nfs_pgio_data *data, \
int error \ int error \
), \ ), \
TP_ARGS(data, error)) TP_ARGS(data, error))
......
...@@ -1556,7 +1556,8 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) ...@@ -1556,7 +1556,8 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr); encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
} }
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) static void encode_read(struct xdr_stream *xdr, const struct nfs_pgio_args *args,
struct compound_hdr *hdr)
{ {
__be32 *p; __be32 *p;
...@@ -1701,7 +1702,8 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4 ...@@ -1701,7 +1702,8 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4
encode_nfs4_verifier(xdr, &arg->confirm); encode_nfs4_verifier(xdr, &arg->confirm);
} }
static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) static void encode_write(struct xdr_stream *xdr, const struct nfs_pgio_args *args,
struct compound_hdr *hdr)
{ {
__be32 *p; __be32 *p;
...@@ -2451,7 +2453,7 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -2451,7 +2453,7 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
* Encode a READ request * Encode a READ request
*/ */
static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr, static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_readargs *args) struct nfs_pgio_args *args)
{ {
struct compound_hdr hdr = { struct compound_hdr hdr = {
.minorversion = nfs4_xdr_minorversion(&args->seq_args), .minorversion = nfs4_xdr_minorversion(&args->seq_args),
...@@ -2513,7 +2515,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -2513,7 +2515,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
* Encode a WRITE request * Encode a WRITE request
*/ */
static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr, static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_writeargs *args) struct nfs_pgio_args *args)
{ {
struct compound_hdr hdr = { struct compound_hdr hdr = {
.minorversion = nfs4_xdr_minorversion(&args->seq_args), .minorversion = nfs4_xdr_minorversion(&args->seq_args),
...@@ -5085,7 +5087,8 @@ static int decode_putrootfh(struct xdr_stream *xdr) ...@@ -5085,7 +5087,8 @@ static int decode_putrootfh(struct xdr_stream *xdr)
return decode_op_hdr(xdr, OP_PUTROOTFH); return decode_op_hdr(xdr, OP_PUTROOTFH);
} }
static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req,
struct nfs_pgio_res *res)
{ {
__be32 *p; __be32 *p;
uint32_t count, eof, recvd; uint32_t count, eof, recvd;
...@@ -5339,7 +5342,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr) ...@@ -5339,7 +5342,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr)
return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM); return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
} }
static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) static int decode_write(struct xdr_stream *xdr, struct nfs_pgio_res *res)
{ {
__be32 *p; __be32 *p;
int status; int status;
...@@ -6636,7 +6639,7 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -6636,7 +6639,7 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
* Decode Read response * Decode Read response
*/ */
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr, static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
struct nfs_readres *res) struct nfs_pgio_res *res)
{ {
struct compound_hdr hdr; struct compound_hdr hdr;
int status; int status;
...@@ -6661,7 +6664,7 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -6661,7 +6664,7 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
* Decode WRITE response * Decode WRITE response
*/ */
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr, static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
struct nfs_writeres *res) struct nfs_pgio_res *res)
{ {
struct compound_hdr hdr; struct compound_hdr hdr;
int status; int status;
......
...@@ -439,7 +439,7 @@ static void _read_done(struct ore_io_state *ios, void *private) ...@@ -439,7 +439,7 @@ static void _read_done(struct ore_io_state *ios, void *private)
objlayout_read_done(&objios->oir, status, objios->sync); objlayout_read_done(&objios->oir, status, objios->sync);
} }
int objio_read_pagelist(struct nfs_read_data *rdata) int objio_read_pagelist(struct nfs_pgio_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header; struct nfs_pgio_header *hdr = rdata->header;
struct objio_state *objios; struct objio_state *objios;
...@@ -487,7 +487,7 @@ static void _write_done(struct ore_io_state *ios, void *private) ...@@ -487,7 +487,7 @@ static void _write_done(struct ore_io_state *ios, void *private)
static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
{ {
struct objio_state *objios = priv; struct objio_state *objios = priv;
struct nfs_write_data *wdata = objios->oir.rpcdata; struct nfs_pgio_data *wdata = objios->oir.rpcdata;
struct address_space *mapping = wdata->header->inode->i_mapping; struct address_space *mapping = wdata->header->inode->i_mapping;
pgoff_t index = offset / PAGE_SIZE; pgoff_t index = offset / PAGE_SIZE;
struct page *page; struct page *page;
...@@ -531,7 +531,7 @@ static const struct _ore_r4w_op _r4w_op = { ...@@ -531,7 +531,7 @@ static const struct _ore_r4w_op _r4w_op = {
.put_page = &__r4w_put_page, .put_page = &__r4w_put_page,
}; };
int objio_write_pagelist(struct nfs_write_data *wdata, int how) int objio_write_pagelist(struct nfs_pgio_data *wdata, int how)
{ {
struct nfs_pgio_header *hdr = wdata->header; struct nfs_pgio_header *hdr = wdata->header;
struct objio_state *objios; struct objio_state *objios;
...@@ -564,14 +564,22 @@ int objio_write_pagelist(struct nfs_write_data *wdata, int how) ...@@ -564,14 +564,22 @@ int objio_write_pagelist(struct nfs_write_data *wdata, int how)
return 0; return 0;
} }
static bool objio_pg_test(struct nfs_pageio_descriptor *pgio, /*
* Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
* of bytes (maximum @req->wb_bytes) that can be coalesced.
*/
static size_t objio_pg_test(struct nfs_pageio_descriptor *pgio,
struct nfs_page *prev, struct nfs_page *req) struct nfs_page *prev, struct nfs_page *req)
{ {
if (!pnfs_generic_pg_test(pgio, prev, req)) unsigned int size;
return false;
size = pnfs_generic_pg_test(pgio, prev, req);
if (!size || pgio->pg_count + req->wb_bytes >
(unsigned long)pgio->pg_layout_private)
return 0;
return pgio->pg_count + req->wb_bytes <= return min(size, req->wb_bytes);
(unsigned long)pgio->pg_layout_private;
} }
static void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) static void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
......
...@@ -53,10 +53,10 @@ objlayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) ...@@ -53,10 +53,10 @@ objlayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
struct objlayout *objlay; struct objlayout *objlay;
objlay = kzalloc(sizeof(struct objlayout), gfp_flags); objlay = kzalloc(sizeof(struct objlayout), gfp_flags);
if (objlay) { if (!objlay)
spin_lock_init(&objlay->lock); return NULL;
INIT_LIST_HEAD(&objlay->err_list); spin_lock_init(&objlay->lock);
} INIT_LIST_HEAD(&objlay->err_list);
dprintk("%s: Return %p\n", __func__, objlay); dprintk("%s: Return %p\n", __func__, objlay);
return &objlay->pnfs_layout; return &objlay->pnfs_layout;
} }
...@@ -229,11 +229,11 @@ objlayout_io_set_result(struct objlayout_io_res *oir, unsigned index, ...@@ -229,11 +229,11 @@ objlayout_io_set_result(struct objlayout_io_res *oir, unsigned index,
static void _rpc_read_complete(struct work_struct *work) static void _rpc_read_complete(struct work_struct *work)
{ {
struct rpc_task *task; struct rpc_task *task;
struct nfs_read_data *rdata; struct nfs_pgio_data *rdata;
dprintk("%s enter\n", __func__); dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work); task = container_of(work, struct rpc_task, u.tk_work);
rdata = container_of(task, struct nfs_read_data, task); rdata = container_of(task, struct nfs_pgio_data, task);
pnfs_ld_read_done(rdata); pnfs_ld_read_done(rdata);
} }
...@@ -241,7 +241,7 @@ static void _rpc_read_complete(struct work_struct *work) ...@@ -241,7 +241,7 @@ static void _rpc_read_complete(struct work_struct *work)
void void
objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
{ {
struct nfs_read_data *rdata = oir->rpcdata; struct nfs_pgio_data *rdata = oir->rpcdata;
oir->status = rdata->task.tk_status = status; oir->status = rdata->task.tk_status = status;
if (status >= 0) if (status >= 0)
...@@ -266,7 +266,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -266,7 +266,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
* Perform sync or async reads. * Perform sync or async reads.
*/ */
enum pnfs_try_status enum pnfs_try_status
objlayout_read_pagelist(struct nfs_read_data *rdata) objlayout_read_pagelist(struct nfs_pgio_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header; struct nfs_pgio_header *hdr = rdata->header;
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
...@@ -312,11 +312,11 @@ objlayout_read_pagelist(struct nfs_read_data *rdata) ...@@ -312,11 +312,11 @@ objlayout_read_pagelist(struct nfs_read_data *rdata)
static void _rpc_write_complete(struct work_struct *work) static void _rpc_write_complete(struct work_struct *work)
{ {
struct rpc_task *task; struct rpc_task *task;
struct nfs_write_data *wdata; struct nfs_pgio_data *wdata;
dprintk("%s enter\n", __func__); dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work); task = container_of(work, struct rpc_task, u.tk_work);
wdata = container_of(task, struct nfs_write_data, task); wdata = container_of(task, struct nfs_pgio_data, task);
pnfs_ld_write_done(wdata); pnfs_ld_write_done(wdata);
} }
...@@ -324,7 +324,7 @@ static void _rpc_write_complete(struct work_struct *work) ...@@ -324,7 +324,7 @@ static void _rpc_write_complete(struct work_struct *work)
void void
objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
{ {
struct nfs_write_data *wdata = oir->rpcdata; struct nfs_pgio_data *wdata = oir->rpcdata;
oir->status = wdata->task.tk_status = status; oir->status = wdata->task.tk_status = status;
if (status >= 0) { if (status >= 0) {
...@@ -351,7 +351,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -351,7 +351,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
* Perform sync or async writes. * Perform sync or async writes.
*/ */
enum pnfs_try_status enum pnfs_try_status
objlayout_write_pagelist(struct nfs_write_data *wdata, objlayout_write_pagelist(struct nfs_pgio_data *wdata,
int how) int how)
{ {
struct nfs_pgio_header *hdr = wdata->header; struct nfs_pgio_header *hdr = wdata->header;
......
...@@ -119,8 +119,8 @@ extern void objio_free_lseg(struct pnfs_layout_segment *lseg); ...@@ -119,8 +119,8 @@ extern void objio_free_lseg(struct pnfs_layout_segment *lseg);
*/ */
extern void objio_free_result(struct objlayout_io_res *oir); extern void objio_free_result(struct objlayout_io_res *oir);
extern int objio_read_pagelist(struct nfs_read_data *rdata); extern int objio_read_pagelist(struct nfs_pgio_data *rdata);
extern int objio_write_pagelist(struct nfs_write_data *wdata, int how); extern int objio_write_pagelist(struct nfs_pgio_data *wdata, int how);
/* /*
* callback API * callback API
...@@ -168,10 +168,10 @@ extern struct pnfs_layout_segment *objlayout_alloc_lseg( ...@@ -168,10 +168,10 @@ extern struct pnfs_layout_segment *objlayout_alloc_lseg(
extern void objlayout_free_lseg(struct pnfs_layout_segment *); extern void objlayout_free_lseg(struct pnfs_layout_segment *);
extern enum pnfs_try_status objlayout_read_pagelist( extern enum pnfs_try_status objlayout_read_pagelist(
struct nfs_read_data *); struct nfs_pgio_data *);
extern enum pnfs_try_status objlayout_write_pagelist( extern enum pnfs_try_status objlayout_write_pagelist(
struct nfs_write_data *, struct nfs_pgio_data *,
int how); int how);
extern void objlayout_encode_layoutcommit( extern void objlayout_encode_layoutcommit(
......
此差异已折叠。
...@@ -1388,11 +1388,6 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r ...@@ -1388,11 +1388,6 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
WARN_ON_ONCE(pgio->pg_lseg != NULL); WARN_ON_ONCE(pgio->pg_lseg != NULL);
if (req->wb_offset != req->wb_pgbase) {
nfs_pageio_reset_read_mds(pgio);
return;
}
if (pgio->pg_dreq == NULL) if (pgio->pg_dreq == NULL)
rd_size = i_size_read(pgio->pg_inode) - req_offset(req); rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
else else
...@@ -1417,11 +1412,6 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -1417,11 +1412,6 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
{ {
WARN_ON_ONCE(pgio->pg_lseg != NULL); WARN_ON_ONCE(pgio->pg_lseg != NULL);
if (req->wb_offset != req->wb_pgbase) {
nfs_pageio_reset_write_mds(pgio);
return;
}
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context, req->wb_context,
req_offset(req), req_offset(req),
...@@ -1434,56 +1424,49 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -1434,56 +1424,49 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
} }
EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write); EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
void /*
pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
const struct nfs_pgio_completion_ops *compl_ops) * of bytes (maximum @req->wb_bytes) that can be coalesced.
{ */
struct nfs_server *server = NFS_SERVER(inode); size_t
struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
if (ld == NULL)
nfs_pageio_init_read(pgio, inode, compl_ops);
else
nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops, server->rsize, 0);
}
void
pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode,
int ioflags,
const struct nfs_pgio_completion_ops *compl_ops)
{
struct nfs_server *server = NFS_SERVER(inode);
struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
if (ld == NULL)
nfs_pageio_init_write(pgio, inode, ioflags, compl_ops);
else
nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops, server->wsize, ioflags);
}
bool
pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
struct nfs_page *req) struct nfs_page *req)
{ {
if (pgio->pg_lseg == NULL) unsigned int size;
return nfs_generic_pg_test(pgio, prev, req); u64 seg_end, req_start, seg_left;
size = nfs_generic_pg_test(pgio, prev, req);
if (!size)
return 0;
/* /*
* Test if a nfs_page is fully contained in the pnfs_layout_range. * 'size' contains the number of bytes left in the current page (up
* Note that this test makes several assumptions: * to the original size asked for in @req->wb_bytes).
* - that the previous nfs_page in the struct nfs_pageio_descriptor *
* is known to lie within the range. * Calculate how many bytes are left in the layout segment
* - that the nfs_page being tested is known to be contiguous with the * and if there are less bytes than 'size', return that instead.
* previous nfs_page.
* - Layout ranges are page aligned, so we only have to test the
* start offset of the request.
* *
* Please also note that 'end_offset' is actually the offset of the * Please also note that 'end_offset' is actually the offset of the
* first byte that lies outside the pnfs_layout_range. FIXME? * first byte that lies outside the pnfs_layout_range. FIXME?
* *
*/ */
return req_offset(req) < end_offset(pgio->pg_lseg->pls_range.offset, if (pgio->pg_lseg) {
pgio->pg_lseg->pls_range.length); seg_end = end_offset(pgio->pg_lseg->pls_range.offset,
pgio->pg_lseg->pls_range.length);
req_start = req_offset(req);
WARN_ON_ONCE(req_start > seg_end);
/* start of request is past the last byte of this segment */
if (req_start >= seg_end)
return 0;
/* adjust 'size' iff there are fewer bytes left in the
* segment than what nfs_generic_pg_test returned */
seg_left = seg_end - req_start;
if (seg_left < size)
size = (unsigned int)seg_left;
}
return size;
} }
EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
...@@ -1496,7 +1479,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode, ...@@ -1496,7 +1479,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode,
LIST_HEAD(failed); LIST_HEAD(failed);
/* Resend all requests through the MDS */ /* Resend all requests through the MDS */
nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, true, compl_ops);
pgio.pg_dreq = dreq; pgio.pg_dreq = dreq;
while (!list_empty(head)) { while (!list_empty(head)) {
struct nfs_page *req = nfs_list_entry(head->next); struct nfs_page *req = nfs_list_entry(head->next);
...@@ -1519,7 +1502,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode, ...@@ -1519,7 +1502,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode,
} }
EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds); EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds);
static void pnfs_ld_handle_write_error(struct nfs_write_data *data) static void pnfs_ld_handle_write_error(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1538,7 +1521,7 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) ...@@ -1538,7 +1521,7 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
/* /*
* Called by non rpc-based layout drivers * Called by non rpc-based layout drivers
*/ */
void pnfs_ld_write_done(struct nfs_write_data *data) void pnfs_ld_write_done(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1554,7 +1537,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_write_done); ...@@ -1554,7 +1537,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
static void static void
pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
struct nfs_write_data *data) struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1563,11 +1546,11 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, ...@@ -1563,11 +1546,11 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
nfs_pageio_reset_write_mds(desc); nfs_pageio_reset_write_mds(desc);
desc->pg_recoalesce = 1; desc->pg_recoalesce = 1;
} }
nfs_writedata_release(data); nfs_pgio_data_release(data);
} }
static enum pnfs_try_status static enum pnfs_try_status
pnfs_try_to_write_data(struct nfs_write_data *wdata, pnfs_try_to_write_data(struct nfs_pgio_data *wdata,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
struct pnfs_layout_segment *lseg, struct pnfs_layout_segment *lseg,
int how) int how)
...@@ -1589,41 +1572,36 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata, ...@@ -1589,41 +1572,36 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata,
} }
static void static void
pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how) pnfs_do_write(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr, int how)
{ {
struct nfs_write_data *data; struct nfs_pgio_data *data = hdr->data;
const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
struct pnfs_layout_segment *lseg = desc->pg_lseg; struct pnfs_layout_segment *lseg = desc->pg_lseg;
enum pnfs_try_status trypnfs;
desc->pg_lseg = NULL; desc->pg_lseg = NULL;
while (!list_empty(head)) { trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
enum pnfs_try_status trypnfs; if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_write_through_mds(desc, data);
data = list_first_entry(head, struct nfs_write_data, list);
list_del_init(&data->list);
trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_write_through_mds(desc, data);
}
pnfs_put_lseg(lseg); pnfs_put_lseg(lseg);
} }
static void pnfs_writehdr_free(struct nfs_pgio_header *hdr) static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
{ {
pnfs_put_lseg(hdr->lseg); pnfs_put_lseg(hdr->lseg);
nfs_writehdr_free(hdr); nfs_rw_header_free(hdr);
} }
EXPORT_SYMBOL_GPL(pnfs_writehdr_free); EXPORT_SYMBOL_GPL(pnfs_writehdr_free);
int int
pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
{ {
struct nfs_write_header *whdr; struct nfs_rw_header *whdr;
struct nfs_pgio_header *hdr; struct nfs_pgio_header *hdr;
int ret; int ret;
whdr = nfs_writehdr_alloc(); whdr = nfs_rw_header_alloc(desc->pg_rw_ops);
if (!whdr) { if (!whdr) {
desc->pg_completion_ops->error_cleanup(&desc->pg_list); desc->pg_completion_ops->error_cleanup(&desc->pg_list);
pnfs_put_lseg(desc->pg_lseg); pnfs_put_lseg(desc->pg_lseg);
...@@ -1634,12 +1612,12 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) ...@@ -1634,12 +1612,12 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
hdr->lseg = pnfs_get_lseg(desc->pg_lseg); hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
atomic_inc(&hdr->refcnt); atomic_inc(&hdr->refcnt);
ret = nfs_generic_flush(desc, hdr); ret = nfs_generic_pgio(desc, hdr);
if (ret != 0) { if (ret != 0) {
pnfs_put_lseg(desc->pg_lseg); pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL; desc->pg_lseg = NULL;
} else } else
pnfs_do_multiple_writes(desc, &hdr->rpc_list, desc->pg_ioflags); pnfs_do_write(desc, hdr, desc->pg_ioflags);
if (atomic_dec_and_test(&hdr->refcnt)) if (atomic_dec_and_test(&hdr->refcnt))
hdr->completion_ops->completion(hdr); hdr->completion_ops->completion(hdr);
return ret; return ret;
...@@ -1655,7 +1633,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode, ...@@ -1655,7 +1633,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode,
LIST_HEAD(failed); LIST_HEAD(failed);
/* Resend all requests through the MDS */ /* Resend all requests through the MDS */
nfs_pageio_init_read(&pgio, inode, compl_ops); nfs_pageio_init_read(&pgio, inode, true, compl_ops);
pgio.pg_dreq = dreq; pgio.pg_dreq = dreq;
while (!list_empty(head)) { while (!list_empty(head)) {
struct nfs_page *req = nfs_list_entry(head->next); struct nfs_page *req = nfs_list_entry(head->next);
...@@ -1674,7 +1652,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode, ...@@ -1674,7 +1652,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode,
} }
EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds); EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds);
static void pnfs_ld_handle_read_error(struct nfs_read_data *data) static void pnfs_ld_handle_read_error(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1693,7 +1671,7 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) ...@@ -1693,7 +1671,7 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
/* /*
* Called by non rpc-based layout drivers * Called by non rpc-based layout drivers
*/ */
void pnfs_ld_read_done(struct nfs_read_data *data) void pnfs_ld_read_done(struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1709,7 +1687,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_read_done); ...@@ -1709,7 +1687,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
static void static void
pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
struct nfs_read_data *data) struct nfs_pgio_data *data)
{ {
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
...@@ -1718,14 +1696,14 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, ...@@ -1718,14 +1696,14 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
nfs_pageio_reset_read_mds(desc); nfs_pageio_reset_read_mds(desc);
desc->pg_recoalesce = 1; desc->pg_recoalesce = 1;
} }
nfs_readdata_release(data); nfs_pgio_data_release(data);
} }
/* /*
* Call the appropriate parallel I/O subsystem read function. * Call the appropriate parallel I/O subsystem read function.
*/ */
static enum pnfs_try_status static enum pnfs_try_status
pnfs_try_to_read_data(struct nfs_read_data *rdata, pnfs_try_to_read_data(struct nfs_pgio_data *rdata,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
struct pnfs_layout_segment *lseg) struct pnfs_layout_segment *lseg)
{ {
...@@ -1747,41 +1725,35 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, ...@@ -1747,41 +1725,35 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
} }
static void static void
pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head) pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{ {
struct nfs_read_data *data; struct nfs_pgio_data *data = hdr->data;
const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
struct pnfs_layout_segment *lseg = desc->pg_lseg; struct pnfs_layout_segment *lseg = desc->pg_lseg;
enum pnfs_try_status trypnfs;
desc->pg_lseg = NULL; desc->pg_lseg = NULL;
while (!list_empty(head)) { trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
enum pnfs_try_status trypnfs; if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_read_through_mds(desc, data);
data = list_first_entry(head, struct nfs_read_data, list);
list_del_init(&data->list);
trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_read_through_mds(desc, data);
}
pnfs_put_lseg(lseg); pnfs_put_lseg(lseg);
} }
static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
{ {
pnfs_put_lseg(hdr->lseg); pnfs_put_lseg(hdr->lseg);
nfs_readhdr_free(hdr); nfs_rw_header_free(hdr);
} }
EXPORT_SYMBOL_GPL(pnfs_readhdr_free); EXPORT_SYMBOL_GPL(pnfs_readhdr_free);
int int
pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{ {
struct nfs_read_header *rhdr; struct nfs_rw_header *rhdr;
struct nfs_pgio_header *hdr; struct nfs_pgio_header *hdr;
int ret; int ret;
rhdr = nfs_readhdr_alloc(); rhdr = nfs_rw_header_alloc(desc->pg_rw_ops);
if (!rhdr) { if (!rhdr) {
desc->pg_completion_ops->error_cleanup(&desc->pg_list); desc->pg_completion_ops->error_cleanup(&desc->pg_list);
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1793,12 +1765,12 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) ...@@ -1793,12 +1765,12 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
hdr->lseg = pnfs_get_lseg(desc->pg_lseg); hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
atomic_inc(&hdr->refcnt); atomic_inc(&hdr->refcnt);
ret = nfs_generic_pagein(desc, hdr); ret = nfs_generic_pgio(desc, hdr);
if (ret != 0) { if (ret != 0) {
pnfs_put_lseg(desc->pg_lseg); pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL; desc->pg_lseg = NULL;
} else } else
pnfs_do_multiple_reads(desc, &hdr->rpc_list); pnfs_do_read(desc, hdr);
if (atomic_dec_and_test(&hdr->refcnt)) if (atomic_dec_and_test(&hdr->refcnt))
hdr->completion_ops->completion(hdr); hdr->completion_ops->completion(hdr);
return ret; return ret;
...@@ -1848,7 +1820,7 @@ void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) ...@@ -1848,7 +1820,7 @@ void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
void void
pnfs_set_layoutcommit(struct nfs_write_data *wdata) pnfs_set_layoutcommit(struct nfs_pgio_data *wdata)
{ {
struct nfs_pgio_header *hdr = wdata->header; struct nfs_pgio_header *hdr = wdata->header;
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
......
...@@ -113,8 +113,8 @@ struct pnfs_layoutdriver_type { ...@@ -113,8 +113,8 @@ struct pnfs_layoutdriver_type {
* Return PNFS_ATTEMPTED to indicate the layout code has attempted * Return PNFS_ATTEMPTED to indicate the layout code has attempted
* I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
*/ */
enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data); enum pnfs_try_status (*read_pagelist) (struct nfs_pgio_data *nfs_data);
enum pnfs_try_status (*write_pagelist) (struct nfs_write_data *nfs_data, int how); enum pnfs_try_status (*write_pagelist) (struct nfs_pgio_data *nfs_data, int how);
void (*free_deviceid_node) (struct nfs4_deviceid_node *); void (*free_deviceid_node) (struct nfs4_deviceid_node *);
...@@ -180,11 +180,6 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); ...@@ -180,11 +180,6 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo);
void pnfs_put_lseg(struct pnfs_layout_segment *lseg); void pnfs_put_lseg(struct pnfs_layout_segment *lseg);
void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *,
const struct nfs_pgio_completion_ops *);
void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *,
int, const struct nfs_pgio_completion_ops *);
void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
void unset_pnfs_layoutdriver(struct nfs_server *); void unset_pnfs_layoutdriver(struct nfs_server *);
void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *); void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
...@@ -192,7 +187,8 @@ int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc); ...@@ -192,7 +187,8 @@ int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size); struct nfs_page *req, u64 wb_size);
int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc); int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req); size_t pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio,
struct nfs_page *prev, struct nfs_page *req);
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg); void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg);
struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp); struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp);
void pnfs_free_lseg_list(struct list_head *tmp_list); void pnfs_free_lseg_list(struct list_head *tmp_list);
...@@ -217,13 +213,13 @@ bool pnfs_roc(struct inode *ino); ...@@ -217,13 +213,13 @@ bool pnfs_roc(struct inode *ino);
void pnfs_roc_release(struct inode *ino); void pnfs_roc_release(struct inode *ino);
void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task); bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task);
void pnfs_set_layoutcommit(struct nfs_write_data *wdata); void pnfs_set_layoutcommit(struct nfs_pgio_data *wdata);
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
int pnfs_layoutcommit_inode(struct inode *inode, bool sync); int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
int _pnfs_return_layout(struct inode *); int _pnfs_return_layout(struct inode *);
int pnfs_commit_and_return_layout(struct inode *); int pnfs_commit_and_return_layout(struct inode *);
void pnfs_ld_write_done(struct nfs_write_data *); void pnfs_ld_write_done(struct nfs_pgio_data *);
void pnfs_ld_read_done(struct nfs_read_data *); void pnfs_ld_read_done(struct nfs_pgio_data *);
struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
struct nfs_open_context *ctx, struct nfs_open_context *ctx,
loff_t pos, loff_t pos,
...@@ -461,18 +457,6 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s) ...@@ -461,18 +457,6 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
{ {
} }
static inline void pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
const struct nfs_pgio_completion_ops *compl_ops)
{
nfs_pageio_init_read(pgio, inode, compl_ops);
}
static inline void pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags,
const struct nfs_pgio_completion_ops *compl_ops)
{
nfs_pageio_init_write(pgio, inode, ioflags, compl_ops);
}
static inline int static inline int
pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how, pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how,
struct nfs_commit_info *cinfo) struct nfs_commit_info *cinfo)
......
...@@ -578,7 +578,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -578,7 +578,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return 0; return 0;
} }
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
...@@ -594,18 +594,18 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) ...@@ -594,18 +594,18 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
return 0; return 0;
} }
static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) static void nfs_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
} }
static int nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
rpc_call_start(task); rpc_call_start(task);
return 0; return 0;
} }
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
...@@ -614,19 +614,13 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -614,19 +614,13 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
return 0; return 0;
} }
static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) static void nfs_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
{ {
/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
data->args.stable = NFS_FILE_SYNC; data->args.stable = NFS_FILE_SYNC;
msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
} }
static int nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
{
rpc_call_start(task);
return 0;
}
static void nfs_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) static void nfs_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
{ {
BUG(); BUG();
...@@ -734,13 +728,10 @@ const struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -734,13 +728,10 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.fsinfo = nfs_proc_fsinfo, .fsinfo = nfs_proc_fsinfo,
.pathconf = nfs_proc_pathconf, .pathconf = nfs_proc_pathconf,
.decode_dirent = nfs2_decode_dirent, .decode_dirent = nfs2_decode_dirent,
.pgio_rpc_prepare = nfs_proc_pgio_rpc_prepare,
.read_setup = nfs_proc_read_setup, .read_setup = nfs_proc_read_setup,
.read_pageio_init = nfs_pageio_init_read,
.read_rpc_prepare = nfs_proc_read_rpc_prepare,
.read_done = nfs_read_done, .read_done = nfs_read_done,
.write_setup = nfs_proc_write_setup, .write_setup = nfs_proc_write_setup,
.write_pageio_init = nfs_pageio_init_write,
.write_rpc_prepare = nfs_proc_write_rpc_prepare,
.write_done = nfs_write_done, .write_done = nfs_write_done,
.commit_setup = nfs_proc_commit_setup, .commit_setup = nfs_proc_commit_setup,
.commit_rpc_prepare = nfs_proc_commit_rpc_prepare, .commit_rpc_prepare = nfs_proc_commit_rpc_prepare,
......
...@@ -24,85 +24,24 @@ ...@@ -24,85 +24,24 @@
#include "internal.h" #include "internal.h"
#include "iostat.h" #include "iostat.h"
#include "fscache.h" #include "fscache.h"
#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE #define NFSDBG_FACILITY NFSDBG_PAGECACHE
static const struct nfs_pageio_ops nfs_pageio_read_ops;
static const struct rpc_call_ops nfs_read_common_ops;
static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops; 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 kmem_cache *nfs_rdata_cachep;
struct nfs_read_header *nfs_readhdr_alloc(void) static struct nfs_rw_header *nfs_readhdr_alloc(void)
{ {
struct nfs_read_header *rhdr; return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
rhdr = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
if (rhdr) {
struct nfs_pgio_header *hdr = &rhdr->header;
INIT_LIST_HEAD(&hdr->pages);
INIT_LIST_HEAD(&hdr->rpc_list);
spin_lock_init(&hdr->lock);
atomic_set(&hdr->refcnt, 0);
}
return rhdr;
} }
EXPORT_SYMBOL_GPL(nfs_readhdr_alloc);
static struct nfs_read_data *nfs_readdata_alloc(struct nfs_pgio_header *hdr, static void nfs_readhdr_free(struct nfs_rw_header *rhdr)
unsigned int pagecount)
{ {
struct nfs_read_data *data, *prealloc;
prealloc = &container_of(hdr, struct nfs_read_header, header)->rpc_data;
if (prealloc->header == NULL)
data = prealloc;
else
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
goto out;
if (nfs_pgarray_set(&data->pages, pagecount)) {
data->header = hdr;
atomic_inc(&hdr->refcnt);
} else {
if (data != prealloc)
kfree(data);
data = NULL;
}
out:
return data;
}
void nfs_readhdr_free(struct nfs_pgio_header *hdr)
{
struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header);
kmem_cache_free(nfs_rdata_cachep, rhdr); kmem_cache_free(nfs_rdata_cachep, rhdr);
} }
EXPORT_SYMBOL_GPL(nfs_readhdr_free);
void nfs_readdata_release(struct nfs_read_data *rdata)
{
struct nfs_pgio_header *hdr = rdata->header;
struct nfs_read_header *read_header = container_of(hdr, struct nfs_read_header, header);
put_nfs_open_context(rdata->args.context);
if (rdata->pages.pagevec != rdata->pages.page_array)
kfree(rdata->pages.pagevec);
if (rdata == &read_header->rpc_data) {
rdata->header = NULL;
rdata = NULL;
}
if (atomic_dec_and_test(&hdr->refcnt))
hdr->completion_ops->completion(hdr);
/* Note: we only free the rpc_task after callbacks are done.
* See the comment in rpc_free_task() for why
*/
kfree(rdata);
}
EXPORT_SYMBOL_GPL(nfs_readdata_release);
static static
int nfs_return_empty_page(struct page *page) int nfs_return_empty_page(struct page *page)
...@@ -114,17 +53,24 @@ int nfs_return_empty_page(struct page *page) ...@@ -114,17 +53,24 @@ int nfs_return_empty_page(struct page *page)
} }
void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
struct inode *inode, struct inode *inode, bool force_mds,
const struct nfs_pgio_completion_ops *compl_ops) const struct nfs_pgio_completion_ops *compl_ops)
{ {
nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, compl_ops, struct nfs_server *server = NFS_SERVER(inode);
NFS_SERVER(inode)->rsize, 0); 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); EXPORT_SYMBOL_GPL(nfs_pageio_init_read);
void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
{ {
pgio->pg_ops = &nfs_pageio_read_ops; pgio->pg_ops = &nfs_pgio_rw_ops;
pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
} }
EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
...@@ -139,7 +85,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, ...@@ -139,7 +85,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
len = nfs_page_length(page); len = nfs_page_length(page);
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); return nfs_return_empty_page(page);
new = nfs_create_request(ctx, inode, page, 0, len); new = nfs_create_request(ctx, page, NULL, 0, len);
if (IS_ERR(new)) { if (IS_ERR(new)) {
unlock_page(page); unlock_page(page);
return PTR_ERR(new); return PTR_ERR(new);
...@@ -147,7 +93,8 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, ...@@ -147,7 +93,8 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
if (len < PAGE_CACHE_SIZE) if (len < PAGE_CACHE_SIZE)
zero_user_segment(page, len, PAGE_CACHE_SIZE); zero_user_segment(page, len, PAGE_CACHE_SIZE);
NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); nfs_pageio_init_read(&pgio, inode, false,
&nfs_async_read_completion_ops);
nfs_pageio_add_request(&pgio, new); nfs_pageio_add_request(&pgio, new);
nfs_pageio_complete(&pgio); nfs_pageio_complete(&pgio);
NFS_I(inode)->read_io += pgio.pg_bytes_written; NFS_I(inode)->read_io += pgio.pg_bytes_written;
...@@ -158,10 +105,16 @@ static void nfs_readpage_release(struct nfs_page *req) ...@@ -158,10 +105,16 @@ static void nfs_readpage_release(struct nfs_page *req)
{ {
struct inode *d_inode = req->wb_context->dentry->d_inode; struct inode *d_inode = req->wb_context->dentry->d_inode;
if (PageUptodate(req->wb_page)) dprintk("NFS: read done (%s/%llu %d@%lld)\n", d_inode->i_sb->s_id,
nfs_readpage_to_fscache(d_inode, req->wb_page, 0); (unsigned long long)NFS_FILEID(d_inode), req->wb_bytes,
(long long)req_offset(req));
unlock_page(req->wb_page); if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
if (PageUptodate(req->wb_page))
nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
unlock_page(req->wb_page);
}
dprintk("NFS: read done (%s/%Lu %d@%Ld)\n", dprintk("NFS: read done (%s/%Lu %d@%Ld)\n",
req->wb_context->dentry->d_inode->i_sb->s_id, req->wb_context->dentry->d_inode->i_sb->s_id,
...@@ -171,7 +124,12 @@ static void nfs_readpage_release(struct nfs_page *req) ...@@ -171,7 +124,12 @@ static void nfs_readpage_release(struct nfs_page *req)
nfs_release_request(req); nfs_release_request(req);
} }
/* Note io was page aligned */ static void nfs_page_group_set_uptodate(struct nfs_page *req)
{
if (nfs_page_group_sync_on_bit(req, PG_UPTODATE))
SetPageUptodate(req->wb_page);
}
static void nfs_read_completion(struct nfs_pgio_header *hdr) static void nfs_read_completion(struct nfs_pgio_header *hdr)
{ {
unsigned long bytes = 0; unsigned long bytes = 0;
...@@ -181,21 +139,32 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr) ...@@ -181,21 +139,32 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
while (!list_empty(&hdr->pages)) { while (!list_empty(&hdr->pages)) {
struct nfs_page *req = nfs_list_entry(hdr->pages.next); struct nfs_page *req = nfs_list_entry(hdr->pages.next);
struct page *page = req->wb_page; struct page *page = req->wb_page;
unsigned long start = req->wb_pgbase;
unsigned long end = req->wb_pgbase + req->wb_bytes;
if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) {
if (bytes > hdr->good_bytes) /* note: regions of the page not covered by a
zero_user(page, 0, PAGE_SIZE); * request are zeroed in nfs_readpage_async /
else if (hdr->good_bytes - bytes < PAGE_SIZE) * readpage_async_filler */
zero_user_segment(page, if (bytes > hdr->good_bytes) {
hdr->good_bytes & ~PAGE_MASK, /* nothing in this request was good, so zero
PAGE_SIZE); * the full extent of the request */
zero_user_segment(page, start, end);
} else if (hdr->good_bytes - bytes < req->wb_bytes) {
/* part of this request has good bytes, but
* not all. zero the bad bytes */
start += hdr->good_bytes - bytes;
WARN_ON(start < req->wb_pgbase);
zero_user_segment(page, start, end);
}
} }
bytes += req->wb_bytes; bytes += req->wb_bytes;
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
if (bytes <= hdr->good_bytes) if (bytes <= hdr->good_bytes)
SetPageUptodate(page); nfs_page_group_set_uptodate(req);
} else } else
SetPageUptodate(page); nfs_page_group_set_uptodate(req);
nfs_list_remove_request(req); nfs_list_remove_request(req);
nfs_readpage_release(req); nfs_readpage_release(req);
} }
...@@ -203,95 +172,14 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr) ...@@ -203,95 +172,14 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
hdr->release(hdr); hdr->release(hdr);
} }
int nfs_initiate_read(struct rpc_clnt *clnt, static void nfs_initiate_read(struct nfs_pgio_data *data, struct rpc_message *msg,
struct nfs_read_data *data, struct rpc_task_setup *task_setup_data, int how)
const struct rpc_call_ops *call_ops, int flags)
{ {
struct inode *inode = data->header->inode; struct inode *inode = data->header->inode;
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
struct rpc_task *task;
struct rpc_message msg = {
.rpc_argp = &data->args,
.rpc_resp = &data->res,
.rpc_cred = data->header->cred,
};
struct rpc_task_setup task_setup_data = {
.task = &data->task,
.rpc_client = clnt,
.rpc_message = &msg,
.callback_ops = call_ops,
.callback_data = data,
.workqueue = nfsiod_workqueue,
.flags = RPC_TASK_ASYNC | swap_flags | flags,
};
/* Set up the initial task struct. */ task_setup_data->flags |= swap_flags;
NFS_PROTO(inode)->read_setup(data, &msg); NFS_PROTO(inode)->read_setup(data, msg);
dprintk("NFS: %5u initiated read call (req %s/%llu, %u bytes @ "
"offset %llu)\n",
data->task.tk_pid,
inode->i_sb->s_id,
(unsigned long long)NFS_FILEID(inode),
data->args.count,
(unsigned long long)data->args.offset);
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return PTR_ERR(task);
rpc_put_task(task);
return 0;
}
EXPORT_SYMBOL_GPL(nfs_initiate_read);
/*
* Set up the NFS read request struct
*/
static void nfs_read_rpcsetup(struct nfs_read_data *data,
unsigned int count, unsigned int offset)
{
struct nfs_page *req = data->header->req;
data->args.fh = NFS_FH(data->header->inode);
data->args.offset = req_offset(req) + offset;
data->args.pgbase = req->wb_pgbase + offset;
data->args.pages = data->pages.pagevec;
data->args.count = count;
data->args.context = get_nfs_open_context(req->wb_context);
data->args.lock_context = req->wb_lock_context;
data->res.fattr = &data->fattr;
data->res.count = count;
data->res.eof = 0;
nfs_fattr_init(&data->fattr);
}
static int nfs_do_read(struct nfs_read_data *data,
const struct rpc_call_ops *call_ops)
{
struct inode *inode = data->header->inode;
return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops, 0);
}
static int
nfs_do_multiple_reads(struct list_head *head,
const struct rpc_call_ops *call_ops)
{
struct nfs_read_data *data;
int ret = 0;
while (!list_empty(head)) {
int ret2;
data = list_first_entry(head, struct nfs_read_data, list);
list_del_init(&data->list);
ret2 = nfs_do_read(data, call_ops);
if (ret == 0)
ret = ret2;
}
return ret;
} }
static void static void
...@@ -311,143 +199,14 @@ static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = { ...@@ -311,143 +199,14 @@ static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = {
.completion = nfs_read_completion, .completion = nfs_read_completion,
}; };
static void nfs_pagein_error(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
set_bit(NFS_IOHDR_REDO, &hdr->flags);
while (!list_empty(&hdr->rpc_list)) {
struct nfs_read_data *data = list_first_entry(&hdr->rpc_list,
struct nfs_read_data, list);
list_del(&data->list);
nfs_readdata_release(data);
}
desc->pg_completion_ops->error_cleanup(&desc->pg_list);
}
/*
* Generate multiple requests to fill a single page.
*
* We optimize to reduce the number of read operations on the wire. If we
* detect that we're reading a page, or an area of a page, that is past the
* end of file, we do not generate NFS read operations but just clear the
* parts of the page that would have come back zero from the server anyway.
*
* We rely on the cached value of i_size to make this determination; another
* client can fill pages on the server past our cached end-of-file, but we
* won't see the new data until our attribute cache is updated. This is more
* or less conventional NFS client behavior.
*/
static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
struct nfs_page *req = hdr->req;
struct page *page = req->wb_page;
struct nfs_read_data *data;
size_t rsize = desc->pg_bsize, nbytes;
unsigned int offset;
offset = 0;
nbytes = desc->pg_count;
do {
size_t len = min(nbytes,rsize);
data = nfs_readdata_alloc(hdr, 1);
if (!data) {
nfs_pagein_error(desc, hdr);
return -ENOMEM;
}
data->pages.pagevec[0] = page;
nfs_read_rpcsetup(data, len, offset);
list_add(&data->list, &hdr->rpc_list);
nbytes -= len;
offset += len;
} while (nbytes != 0);
nfs_list_remove_request(req);
nfs_list_add_request(req, &hdr->pages);
desc->pg_rpc_callops = &nfs_read_common_ops;
return 0;
}
static int nfs_pagein_one(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
struct nfs_page *req;
struct page **pages;
struct nfs_read_data *data;
struct list_head *head = &desc->pg_list;
data = nfs_readdata_alloc(hdr, nfs_page_array_len(desc->pg_base,
desc->pg_count));
if (!data) {
nfs_pagein_error(desc, hdr);
return -ENOMEM;
}
pages = data->pages.pagevec;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &hdr->pages);
*pages++ = req->wb_page;
}
nfs_read_rpcsetup(data, desc->pg_count, 0);
list_add(&data->list, &hdr->rpc_list);
desc->pg_rpc_callops = &nfs_read_common_ops;
return 0;
}
int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
if (desc->pg_bsize < PAGE_CACHE_SIZE)
return nfs_pagein_multi(desc, hdr);
return nfs_pagein_one(desc, hdr);
}
EXPORT_SYMBOL_GPL(nfs_generic_pagein);
static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{
struct nfs_read_header *rhdr;
struct nfs_pgio_header *hdr;
int ret;
rhdr = nfs_readhdr_alloc();
if (!rhdr) {
desc->pg_completion_ops->error_cleanup(&desc->pg_list);
return -ENOMEM;
}
hdr = &rhdr->header;
nfs_pgheader_init(desc, hdr, nfs_readhdr_free);
atomic_inc(&hdr->refcnt);
ret = nfs_generic_pagein(desc, hdr);
if (ret == 0)
ret = nfs_do_multiple_reads(&hdr->rpc_list,
desc->pg_rpc_callops);
if (atomic_dec_and_test(&hdr->refcnt))
hdr->completion_ops->completion(hdr);
return ret;
}
static const struct nfs_pageio_ops nfs_pageio_read_ops = {
.pg_test = nfs_generic_pg_test,
.pg_doio = nfs_generic_pg_readpages,
};
/* /*
* This is the callback from RPC telling us whether a reply was * This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown). * received or some error occurred (timeout or socket shutdown).
*/ */
int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) static int nfs_readpage_done(struct rpc_task *task, struct nfs_pgio_data *data,
struct inode *inode)
{ {
struct inode *inode = data->header->inode; int status = NFS_PROTO(inode)->read_done(task, data);
int status;
dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid,
task->tk_status);
status = NFS_PROTO(inode)->read_done(task, data);
if (status != 0) if (status != 0)
return status; return status;
...@@ -460,10 +219,10 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) ...@@ -460,10 +219,10 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
return 0; return 0;
} }
static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) static void nfs_readpage_retry(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct nfs_readargs *argp = &data->args; struct nfs_pgio_args *argp = &data->args;
struct nfs_readres *resp = &data->res; struct nfs_pgio_res *resp = &data->res;
/* This is a short read! */ /* This is a short read! */
nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD);
...@@ -480,17 +239,11 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data ...@@ -480,17 +239,11 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
} }
static void nfs_readpage_result_common(struct rpc_task *task, void *calldata) static void nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_data *data)
{ {
struct nfs_read_data *data = calldata;
struct nfs_pgio_header *hdr = data->header; struct nfs_pgio_header *hdr = data->header;
/* Note the only returns of nfs_readpage_result are 0 and -EAGAIN */ if (data->res.eof) {
if (nfs_readpage_result(task, data) != 0)
return;
if (task->tk_status < 0)
nfs_set_pgio_error(hdr, task->tk_status, data->args.offset);
else if (data->res.eof) {
loff_t bound; loff_t bound;
bound = data->args.offset + data->res.count; bound = data->args.offset + data->res.count;
...@@ -505,26 +258,6 @@ static void nfs_readpage_result_common(struct rpc_task *task, void *calldata) ...@@ -505,26 +258,6 @@ static void nfs_readpage_result_common(struct rpc_task *task, void *calldata)
nfs_readpage_retry(task, data); nfs_readpage_retry(task, data);
} }
static void nfs_readpage_release_common(void *calldata)
{
nfs_readdata_release(calldata);
}
void nfs_read_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
int err;
err = NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
if (err)
rpc_exit(task, err);
}
static const struct rpc_call_ops nfs_read_common_ops = {
.rpc_call_prepare = nfs_read_prepare,
.rpc_call_done = nfs_readpage_result_common,
.rpc_release = nfs_readpage_release_common,
};
/* /*
* Read a page over NFS. * Read a page over NFS.
* We read the page synchronously in the following case: * We read the page synchronously in the following case:
...@@ -592,7 +325,6 @@ static int ...@@ -592,7 +325,6 @@ static int
readpage_async_filler(void *data, struct page *page) readpage_async_filler(void *data, struct page *page)
{ {
struct nfs_readdesc *desc = (struct nfs_readdesc *)data; struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *new; struct nfs_page *new;
unsigned int len; unsigned int len;
int error; int error;
...@@ -601,7 +333,7 @@ readpage_async_filler(void *data, struct page *page) ...@@ -601,7 +333,7 @@ readpage_async_filler(void *data, struct page *page)
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); return nfs_return_empty_page(page);
new = nfs_create_request(desc->ctx, inode, page, 0, len); new = nfs_create_request(desc->ctx, page, NULL, 0, len);
if (IS_ERR(new)) if (IS_ERR(new))
goto out_error; goto out_error;
...@@ -654,7 +386,8 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -654,7 +386,8 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
if (ret == 0) if (ret == 0)
goto read_complete; /* all pages were read */ goto read_complete; /* all pages were read */
NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); nfs_pageio_init_read(&pgio, inode, false,
&nfs_async_read_completion_ops);
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
...@@ -671,7 +404,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -671,7 +404,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
int __init nfs_init_readpagecache(void) int __init nfs_init_readpagecache(void)
{ {
nfs_rdata_cachep = kmem_cache_create("nfs_read_data", nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
sizeof(struct nfs_read_header), sizeof(struct nfs_rw_header),
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL); NULL);
if (nfs_rdata_cachep == NULL) if (nfs_rdata_cachep == NULL)
...@@ -684,3 +417,12 @@ void nfs_destroy_readpagecache(void) ...@@ -684,3 +417,12 @@ void nfs_destroy_readpagecache(void)
{ {
kmem_cache_destroy(nfs_rdata_cachep); kmem_cache_destroy(nfs_rdata_cachep);
} }
static const struct nfs_rw_ops nfs_rw_read_ops = {
.rw_mode = FMODE_READ,
.rw_alloc_header = nfs_readhdr_alloc,
.rw_free_header = nfs_readhdr_free,
.rw_done = nfs_readpage_done,
.rw_result = nfs_readpage_result,
.rw_initiate = nfs_initiate_read,
};
...@@ -2180,11 +2180,23 @@ static int nfs_validate_text_mount_data(void *options, ...@@ -2180,11 +2180,23 @@ static int nfs_validate_text_mount_data(void *options,
return -EINVAL; return -EINVAL;
} }
#define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
| NFS_MOUNT_SECURE \
| NFS_MOUNT_TCP \
| NFS_MOUNT_VER3 \
| NFS_MOUNT_KERBEROS \
| NFS_MOUNT_NONLM \
| NFS_MOUNT_BROKEN_SUID \
| NFS_MOUNT_STRICTLOCK \
| NFS_MOUNT_UNSHARED \
| NFS_MOUNT_NORESVPORT \
| NFS_MOUNT_LEGACY_INTERFACE)
static int static int
nfs_compare_remount_data(struct nfs_server *nfss, nfs_compare_remount_data(struct nfs_server *nfss,
struct nfs_parsed_mount_data *data) struct nfs_parsed_mount_data *data)
{ {
if (data->flags != nfss->flags || if ((data->flags ^ nfss->flags) & NFS_MOUNT_CMP_FLAGMASK ||
data->rsize != nfss->rsize || data->rsize != nfss->rsize ||
data->wsize != nfss->wsize || data->wsize != nfss->wsize ||
data->version != nfss->nfs_client->rpc_ops->version || data->version != nfss->nfs_client->rpc_ops->version ||
...@@ -2248,6 +2260,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) ...@@ -2248,6 +2260,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
data->version = nfsvers; data->version = nfsvers;
data->minorversion = nfss->nfs_client->cl_minorversion; data->minorversion = nfss->nfs_client->cl_minorversion;
data->net = current->nsproxy->net_ns;
memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
data->nfs_server.addrlen); data->nfs_server.addrlen);
...@@ -2347,18 +2360,6 @@ void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info) ...@@ -2347,18 +2360,6 @@ void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info)
nfs_initialise_sb(sb); nfs_initialise_sb(sb);
} }
#define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
| NFS_MOUNT_SECURE \
| NFS_MOUNT_TCP \
| NFS_MOUNT_VER3 \
| NFS_MOUNT_KERBEROS \
| NFS_MOUNT_NONLM \
| NFS_MOUNT_BROKEN_SUID \
| NFS_MOUNT_STRICTLOCK \
| NFS_MOUNT_UNSHARED \
| NFS_MOUNT_NORESVPORT \
| NFS_MOUNT_LEGACY_INTERFACE)
static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
{ {
const struct nfs_server *a = s->s_fs_info; const struct nfs_server *a = s->s_fs_info;
......
此差异已折叠。
...@@ -46,6 +46,9 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc ...@@ -46,6 +46,9 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc
enum nfs3_stable_how { enum nfs3_stable_how {
NFS_UNSTABLE = 0, NFS_UNSTABLE = 0,
NFS_DATA_SYNC = 1, NFS_DATA_SYNC = 1,
NFS_FILE_SYNC = 2 NFS_FILE_SYNC = 2,
/* used by direct.c to mark verf as invalid */
NFS_INVALID_STABLE_HOW = -1
}; };
#endif /* _LINUX_NFS_H */ #endif /* _LINUX_NFS_H */
...@@ -520,7 +520,6 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc); ...@@ -520,7 +520,6 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc);
extern int nfs_writepages(struct address_space *, struct writeback_control *); extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern void nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
/* /*
* Try to write back everything synchronously (but check the * Try to write back everything synchronously (but check the
...@@ -553,7 +552,6 @@ nfs_have_writebacks(struct inode *inode) ...@@ -553,7 +552,6 @@ nfs_have_writebacks(struct inode *inode)
extern int nfs_readpage(struct file *, struct page *); extern int nfs_readpage(struct file *, struct page *);
extern int nfs_readpages(struct file *, struct address_space *, extern int nfs_readpages(struct file *, struct address_space *,
struct list_head *, unsigned); struct list_head *, unsigned);
extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *);
extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, extern int nfs_readpage_async(struct nfs_open_context *, struct inode *,
struct page *); struct page *);
......
...@@ -22,12 +22,17 @@ ...@@ -22,12 +22,17 @@
* Valid flags for a dirty buffer * Valid flags for a dirty buffer
*/ */
enum { enum {
PG_BUSY = 0, PG_BUSY = 0, /* nfs_{un}lock_request */
PG_MAPPED, PG_MAPPED, /* page private set for buffered io */
PG_CLEAN, PG_CLEAN, /* write succeeded */
PG_NEED_COMMIT, PG_COMMIT_TO_DS, /* used by pnfs layouts */
PG_NEED_RESCHED, PG_INODE_REF, /* extra ref held by inode (head req only) */
PG_COMMIT_TO_DS, PG_HEADLOCK, /* page group lock of wb_head */
PG_TEARDOWN, /* page group sync for destroy */
PG_UNLOCKPAGE, /* page group sync bit in read path */
PG_UPTODATE, /* page group sync bit in read path */
PG_WB_END, /* page group sync bit in write path */
PG_REMOVE, /* page group sync bit in write path */
}; };
struct nfs_inode; struct nfs_inode;
...@@ -43,15 +48,29 @@ struct nfs_page { ...@@ -43,15 +48,29 @@ struct nfs_page {
struct kref wb_kref; /* reference count */ struct kref wb_kref; /* reference count */
unsigned long wb_flags; unsigned long wb_flags;
struct nfs_write_verifier wb_verf; /* Commit cookie */ struct nfs_write_verifier wb_verf; /* Commit cookie */
struct nfs_page *wb_this_page; /* list of reqs for this page */
struct nfs_page *wb_head; /* head pointer for req list */
}; };
struct nfs_pageio_descriptor; struct nfs_pageio_descriptor;
struct nfs_pageio_ops { struct nfs_pageio_ops {
void (*pg_init)(struct nfs_pageio_descriptor *, struct nfs_page *); void (*pg_init)(struct nfs_pageio_descriptor *, struct nfs_page *);
bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); size_t (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *,
struct nfs_page *);
int (*pg_doio)(struct nfs_pageio_descriptor *); int (*pg_doio)(struct nfs_pageio_descriptor *);
}; };
struct nfs_rw_ops {
const fmode_t rw_mode;
struct nfs_rw_header *(*rw_alloc_header)(void);
void (*rw_free_header)(struct nfs_rw_header *);
void (*rw_release)(struct nfs_pgio_data *);
int (*rw_done)(struct rpc_task *, struct nfs_pgio_data *, struct inode *);
void (*rw_result)(struct rpc_task *, struct nfs_pgio_data *);
void (*rw_initiate)(struct nfs_pgio_data *, struct rpc_message *,
struct rpc_task_setup *, int);
};
struct nfs_pageio_descriptor { struct nfs_pageio_descriptor {
struct list_head pg_list; struct list_head pg_list;
unsigned long pg_bytes_written; unsigned long pg_bytes_written;
...@@ -63,6 +82,7 @@ struct nfs_pageio_descriptor { ...@@ -63,6 +82,7 @@ struct nfs_pageio_descriptor {
struct inode *pg_inode; struct inode *pg_inode;
const struct nfs_pageio_ops *pg_ops; const struct nfs_pageio_ops *pg_ops;
const struct nfs_rw_ops *pg_rw_ops;
int pg_ioflags; int pg_ioflags;
int pg_error; int pg_error;
const struct rpc_call_ops *pg_rpc_callops; const struct rpc_call_ops *pg_rpc_callops;
...@@ -75,29 +95,33 @@ struct nfs_pageio_descriptor { ...@@ -75,29 +95,33 @@ struct nfs_pageio_descriptor {
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx, extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
struct inode *inode,
struct page *page, struct page *page,
struct nfs_page *last,
unsigned int offset, unsigned int offset,
unsigned int count); unsigned int count);
extern void nfs_release_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *);
extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
struct inode *inode, struct inode *inode,
const struct nfs_pageio_ops *pg_ops, const struct nfs_pageio_ops *pg_ops,
const struct nfs_pgio_completion_ops *compl_ops, const struct nfs_pgio_completion_ops *compl_ops,
const struct nfs_rw_ops *rw_ops,
size_t bsize, size_t bsize,
int how); int how);
extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *, extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
struct nfs_page *); struct nfs_page *);
extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t);
extern bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
struct nfs_page *prev, struct nfs_page *prev,
struct nfs_page *req); struct nfs_page *req);
extern int nfs_wait_on_request(struct nfs_page *); extern int nfs_wait_on_request(struct nfs_page *);
extern void nfs_unlock_request(struct nfs_page *req); extern void nfs_unlock_request(struct nfs_page *req);
extern void nfs_unlock_and_release_request(struct nfs_page *req); extern void nfs_unlock_and_release_request(struct nfs_page *);
extern void nfs_page_group_lock(struct nfs_page *);
extern void nfs_page_group_unlock(struct nfs_page *);
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
/* /*
* Lock the page of an asynchronous request * Lock the page of an asynchronous request
......
...@@ -489,31 +489,21 @@ struct nfs4_delegreturnres { ...@@ -489,31 +489,21 @@ struct nfs4_delegreturnres {
}; };
/* /*
* Arguments to the read call. * Arguments to the write call.
*/ */
struct nfs_readargs { struct nfs_write_verifier {
struct nfs4_sequence_args seq_args; char data[8];
struct nfs_fh * fh;
struct nfs_open_context *context;
struct nfs_lock_context *lock_context;
nfs4_stateid stateid;
__u64 offset;
__u32 count;
unsigned int pgbase;
struct page ** pages;
}; };
struct nfs_readres { struct nfs_writeverf {
struct nfs4_sequence_res seq_res; struct nfs_write_verifier verifier;
struct nfs_fattr * fattr; enum nfs3_stable_how committed;
__u32 count;
int eof;
}; };
/* /*
* Arguments to the write call. * Arguments shared by the read and write call.
*/ */
struct nfs_writeargs { struct nfs_pgio_args {
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_open_context *context; struct nfs_open_context *context;
...@@ -521,27 +511,20 @@ struct nfs_writeargs { ...@@ -521,27 +511,20 @@ struct nfs_writeargs {
nfs4_stateid stateid; nfs4_stateid stateid;
__u64 offset; __u64 offset;
__u32 count; __u32 count;
enum nfs3_stable_how stable;
unsigned int pgbase; unsigned int pgbase;
struct page ** pages; struct page ** pages;
const u32 * bitmask; const u32 * bitmask; /* used by write */
}; enum nfs3_stable_how stable; /* used by write */
struct nfs_write_verifier {
char data[8];
}; };
struct nfs_writeverf { struct nfs_pgio_res {
struct nfs_write_verifier verifier;
enum nfs3_stable_how committed;
};
struct nfs_writeres {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs_writeverf * verf;
__u32 count; __u32 count;
const struct nfs_server *server; int eof; /* used by read */
struct nfs_writeverf * verf; /* used by write */
const struct nfs_server *server; /* used by write */
}; };
/* /*
...@@ -1129,6 +1112,7 @@ struct pnfs_commit_bucket { ...@@ -1129,6 +1112,7 @@ struct pnfs_commit_bucket {
struct list_head committing; struct list_head committing;
struct pnfs_layout_segment *wlseg; struct pnfs_layout_segment *wlseg;
struct pnfs_layout_segment *clseg; struct pnfs_layout_segment *clseg;
struct nfs_writeverf direct_verf;
}; };
struct pnfs_ds_commit_info { struct pnfs_ds_commit_info {
...@@ -1264,20 +1248,6 @@ struct nfs_page_array { ...@@ -1264,20 +1248,6 @@ struct nfs_page_array {
struct page *page_array[NFS_PAGEVEC_SIZE]; struct page *page_array[NFS_PAGEVEC_SIZE];
}; };
struct nfs_read_data {
struct nfs_pgio_header *header;
struct list_head list;
struct rpc_task task;
struct nfs_fattr fattr; /* fattr storage */
struct nfs_readargs args;
struct nfs_readres res;
unsigned long timestamp; /* For lease renewal */
int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);
__u64 mds_offset;
struct nfs_page_array pages;
struct nfs_client *ds_clp; /* pNFS data server */
};
/* used as flag bits in nfs_pgio_header */ /* used as flag bits in nfs_pgio_header */
enum { enum {
NFS_IOHDR_ERROR = 0, NFS_IOHDR_ERROR = 0,
...@@ -1287,19 +1257,22 @@ enum { ...@@ -1287,19 +1257,22 @@ enum {
NFS_IOHDR_NEED_RESCHED, NFS_IOHDR_NEED_RESCHED,
}; };
struct nfs_pgio_data;
struct nfs_pgio_header { struct nfs_pgio_header {
struct inode *inode; struct inode *inode;
struct rpc_cred *cred; struct rpc_cred *cred;
struct list_head pages; struct list_head pages;
struct list_head rpc_list; struct nfs_pgio_data *data;
atomic_t refcnt; atomic_t refcnt;
struct nfs_page *req; struct nfs_page *req;
struct nfs_writeverf *verf; struct nfs_writeverf verf; /* Used for writes */
struct pnfs_layout_segment *lseg; struct pnfs_layout_segment *lseg;
loff_t io_start; loff_t io_start;
const struct rpc_call_ops *mds_ops; const struct rpc_call_ops *mds_ops;
void (*release) (struct nfs_pgio_header *hdr); void (*release) (struct nfs_pgio_header *hdr);
const struct nfs_pgio_completion_ops *completion_ops; const struct nfs_pgio_completion_ops *completion_ops;
const struct nfs_rw_ops *rw_ops;
struct nfs_direct_req *dreq; struct nfs_direct_req *dreq;
void *layout_private; void *layout_private;
spinlock_t lock; spinlock_t lock;
...@@ -1310,30 +1283,24 @@ struct nfs_pgio_header { ...@@ -1310,30 +1283,24 @@ struct nfs_pgio_header {
unsigned long flags; unsigned long flags;
}; };
struct nfs_read_header { struct nfs_pgio_data {
struct nfs_pgio_header header;
struct nfs_read_data rpc_data;
};
struct nfs_write_data {
struct nfs_pgio_header *header; struct nfs_pgio_header *header;
struct list_head list;
struct rpc_task task; struct rpc_task task;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct nfs_writeverf verf; struct nfs_writeverf verf; /* Used for writes */
struct nfs_writeargs args; /* argument struct */ struct nfs_pgio_args args; /* argument struct */
struct nfs_writeres res; /* result struct */ struct nfs_pgio_res res; /* result struct */
unsigned long timestamp; /* For lease renewal */ unsigned long timestamp; /* For lease renewal */
int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data); int (*pgio_done_cb) (struct rpc_task *task, struct nfs_pgio_data *data);
__u64 mds_offset; /* Filelayout dense stripe */ __u64 mds_offset; /* Filelayout dense stripe */
struct nfs_page_array pages; struct nfs_page_array pages;
struct nfs_client *ds_clp; /* pNFS data server */ struct nfs_client *ds_clp; /* pNFS data server */
int ds_idx; /* ds index if ds_clp is set */
}; };
struct nfs_write_header { struct nfs_rw_header {
struct nfs_pgio_header header; struct nfs_pgio_header header;
struct nfs_write_data rpc_data; struct nfs_pgio_data rpc_data;
struct nfs_writeverf verf;
}; };
struct nfs_mds_commit_info { struct nfs_mds_commit_info {
...@@ -1465,16 +1432,11 @@ struct nfs_rpc_ops { ...@@ -1465,16 +1432,11 @@ struct nfs_rpc_ops {
struct nfs_pathconf *); struct nfs_pathconf *);
int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); int (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
void (*read_setup) (struct nfs_read_data *, struct rpc_message *); int (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_data *);
void (*read_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, void (*read_setup) (struct nfs_pgio_data *, struct rpc_message *);
const struct nfs_pgio_completion_ops *); int (*read_done) (struct rpc_task *, struct nfs_pgio_data *);
int (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *); void (*write_setup) (struct nfs_pgio_data *, struct rpc_message *);
int (*read_done) (struct rpc_task *, struct nfs_read_data *); int (*write_done) (struct rpc_task *, struct nfs_pgio_data *);
void (*write_setup) (struct nfs_write_data *, struct rpc_message *);
void (*write_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, int,
const struct nfs_pgio_completion_ops *);
int (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
int (*write_done) (struct rpc_task *, struct nfs_write_data *);
void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *);
void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *);
int (*commit_done) (struct rpc_task *, struct nfs_commit_data *); int (*commit_done) (struct rpc_task *, struct nfs_commit_data *);
......
...@@ -24,6 +24,12 @@ ...@@ -24,6 +24,12 @@
#define RPC_MAX_SLOT_TABLE_LIMIT (65536U) #define RPC_MAX_SLOT_TABLE_LIMIT (65536U)
#define RPC_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE_LIMIT #define RPC_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE_LIMIT
#define RPC_CWNDSHIFT (8U)
#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT)
#define RPC_INITCWND RPC_CWNDSCALE
#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT)
#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
/* /*
* This describes a timeout strategy * This describes a timeout strategy
*/ */
......
...@@ -218,10 +218,8 @@ static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor) ...@@ -218,10 +218,8 @@ static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
spin_lock(&registered_mechs_lock); spin_lock(&registered_mechs_lock);
list_for_each_entry(pos, &registered_mechs, gm_list) { list_for_each_entry(pos, &registered_mechs, gm_list) {
if (!mech_supports_pseudoflavor(pos, pseudoflavor)) { if (!mech_supports_pseudoflavor(pos, pseudoflavor))
module_put(pos->gm_owner);
continue; continue;
}
if (try_module_get(pos->gm_owner)) if (try_module_get(pos->gm_owner))
gm = pos; gm = pos;
break; break;
......
...@@ -832,7 +832,8 @@ static void rpc_async_schedule(struct work_struct *work) ...@@ -832,7 +832,8 @@ static void rpc_async_schedule(struct work_struct *work)
* @size: requested byte size * @size: requested byte size
* *
* To prevent rpciod from hanging, this allocator never sleeps, * To prevent rpciod from hanging, this allocator never sleeps,
* returning NULL if the request cannot be serviced immediately. * returning NULL and suppressing warning if the request cannot be serviced
* immediately.
* The caller can arrange to sleep in a way that is safe for rpciod. * The caller can arrange to sleep in a way that is safe for rpciod.
* *
* Most requests are 'small' (under 2KiB) and can be serviced from a * Most requests are 'small' (under 2KiB) and can be serviced from a
...@@ -845,7 +846,7 @@ static void rpc_async_schedule(struct work_struct *work) ...@@ -845,7 +846,7 @@ static void rpc_async_schedule(struct work_struct *work)
void *rpc_malloc(struct rpc_task *task, size_t size) void *rpc_malloc(struct rpc_task *task, size_t size)
{ {
struct rpc_buffer *buf; struct rpc_buffer *buf;
gfp_t gfp = GFP_NOWAIT; gfp_t gfp = GFP_NOWAIT | __GFP_NOWARN;
if (RPC_IS_SWAPPER(task)) if (RPC_IS_SWAPPER(task))
gfp |= __GFP_MEMALLOC; gfp |= __GFP_MEMALLOC;
......
...@@ -71,24 +71,6 @@ static void xprt_destroy(struct rpc_xprt *xprt); ...@@ -71,24 +71,6 @@ static void xprt_destroy(struct rpc_xprt *xprt);
static DEFINE_SPINLOCK(xprt_list_lock); static DEFINE_SPINLOCK(xprt_list_lock);
static LIST_HEAD(xprt_list); static LIST_HEAD(xprt_list);
/*
* The transport code maintains an estimate on the maximum number of out-
* standing RPC requests, using a smoothed version of the congestion
* avoidance implemented in 44BSD. This is basically the Van Jacobson
* congestion algorithm: If a retransmit occurs, the congestion window is
* halved; otherwise, it is incremented by 1/cwnd when
*
* - a reply is received and
* - a full number of requests are outstanding and
* - the congestion window hasn't been updated recently.
*/
#define RPC_CWNDSHIFT (8U)
#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT)
#define RPC_INITCWND RPC_CWNDSCALE
#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT)
#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
/** /**
* xprt_register_transport - register a transport implementation * xprt_register_transport - register a transport implementation
* @transport: transport to register * @transport: transport to register
...@@ -446,7 +428,15 @@ EXPORT_SYMBOL_GPL(xprt_release_rqst_cong); ...@@ -446,7 +428,15 @@ EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
* @task: recently completed RPC request used to adjust window * @task: recently completed RPC request used to adjust window
* @result: result code of completed RPC request * @result: result code of completed RPC request
* *
* We use a time-smoothed congestion estimator to avoid heavy oscillation. * The transport code maintains an estimate on the maximum number of out-
* standing RPC requests, using a smoothed version of the congestion
* avoidance implemented in 44BSD. This is basically the Van Jacobson
* congestion algorithm: If a retransmit occurs, the congestion window is
* halved; otherwise, it is incremented by 1/cwnd when
*
* - a reply is received and
* - a full number of requests are outstanding and
* - the congestion window hasn't been updated recently.
*/ */
void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result) void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result)
{ {
......
...@@ -78,8 +78,7 @@ static const char transfertypes[][12] = { ...@@ -78,8 +78,7 @@ static const char transfertypes[][12] = {
* elements. Segments are then coalesced when registered, if possible * elements. Segments are then coalesced when registered, if possible
* within the selected memreg mode. * within the selected memreg mode.
* *
* Note, this routine is never called if the connection's memory * Returns positive number of segments converted, or a negative errno.
* registration strategy is 0 (bounce buffers).
*/ */
static int static int
...@@ -102,10 +101,17 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, ...@@ -102,10 +101,17 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
page_base = xdrbuf->page_base & ~PAGE_MASK; page_base = xdrbuf->page_base & ~PAGE_MASK;
p = 0; p = 0;
while (len && n < nsegs) { while (len && n < nsegs) {
if (!ppages[p]) {
/* alloc the pagelist for receiving buffer */
ppages[p] = alloc_page(GFP_ATOMIC);
if (!ppages[p])
return -ENOMEM;
}
seg[n].mr_page = ppages[p]; seg[n].mr_page = ppages[p];
seg[n].mr_offset = (void *)(unsigned long) page_base; seg[n].mr_offset = (void *)(unsigned long) page_base;
seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len); seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len);
BUG_ON(seg[n].mr_len > PAGE_SIZE); if (seg[n].mr_len > PAGE_SIZE)
return -EIO;
len -= seg[n].mr_len; len -= seg[n].mr_len;
++n; ++n;
++p; ++p;
...@@ -114,7 +120,7 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, ...@@ -114,7 +120,7 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
/* Message overflows the seg array */ /* Message overflows the seg array */
if (len && n == nsegs) if (len && n == nsegs)
return 0; return -EIO;
if (xdrbuf->tail[0].iov_len) { if (xdrbuf->tail[0].iov_len) {
/* the rpcrdma protocol allows us to omit any trailing /* the rpcrdma protocol allows us to omit any trailing
...@@ -123,7 +129,7 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, ...@@ -123,7 +129,7 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
return n; return n;
if (n == nsegs) if (n == nsegs)
/* Tail remains, but we're out of segments */ /* Tail remains, but we're out of segments */
return 0; return -EIO;
seg[n].mr_page = NULL; seg[n].mr_page = NULL;
seg[n].mr_offset = xdrbuf->tail[0].iov_base; seg[n].mr_offset = xdrbuf->tail[0].iov_base;
seg[n].mr_len = xdrbuf->tail[0].iov_len; seg[n].mr_len = xdrbuf->tail[0].iov_len;
...@@ -164,15 +170,17 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, ...@@ -164,15 +170,17 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
* Reply chunk (a counted array): * Reply chunk (a counted array):
* N elements: * N elements:
* 1 - N - HLOO - HLOO - ... - HLOO * 1 - N - HLOO - HLOO - ... - HLOO
*
* Returns positive RPC/RDMA header size, or negative errno.
*/ */
static unsigned int static ssize_t
rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
struct rpcrdma_msg *headerp, enum rpcrdma_chunktype type) struct rpcrdma_msg *headerp, enum rpcrdma_chunktype type)
{ {
struct rpcrdma_req *req = rpcr_to_rdmar(rqst); struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt); struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
int nsegs, nchunks = 0; int n, nsegs, nchunks = 0;
unsigned int pos; unsigned int pos;
struct rpcrdma_mr_seg *seg = req->rl_segments; struct rpcrdma_mr_seg *seg = req->rl_segments;
struct rpcrdma_read_chunk *cur_rchunk = NULL; struct rpcrdma_read_chunk *cur_rchunk = NULL;
...@@ -198,12 +206,11 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, ...@@ -198,12 +206,11 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
pos = target->head[0].iov_len; pos = target->head[0].iov_len;
nsegs = rpcrdma_convert_iovs(target, pos, type, seg, RPCRDMA_MAX_SEGS); nsegs = rpcrdma_convert_iovs(target, pos, type, seg, RPCRDMA_MAX_SEGS);
if (nsegs == 0) if (nsegs < 0)
return 0; return nsegs;
do { do {
/* bind/register the memory, then build chunk from result. */ n = rpcrdma_register_external(seg, nsegs,
int n = rpcrdma_register_external(seg, nsegs,
cur_wchunk != NULL, r_xprt); cur_wchunk != NULL, r_xprt);
if (n <= 0) if (n <= 0)
goto out; goto out;
...@@ -248,10 +255,6 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, ...@@ -248,10 +255,6 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
/* success. all failures return above */ /* success. all failures return above */
req->rl_nchunks = nchunks; req->rl_nchunks = nchunks;
BUG_ON(nchunks == 0);
BUG_ON((r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR)
&& (nchunks > 3));
/* /*
* finish off header. If write, marshal discrim and nchunks. * finish off header. If write, marshal discrim and nchunks.
*/ */
...@@ -278,8 +281,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, ...@@ -278,8 +281,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
out: out:
for (pos = 0; nchunks--;) for (pos = 0; nchunks--;)
pos += rpcrdma_deregister_external( pos += rpcrdma_deregister_external(
&req->rl_segments[pos], r_xprt, NULL); &req->rl_segments[pos], r_xprt);
return 0; return n;
} }
/* /*
...@@ -361,6 +364,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) ...@@ -361,6 +364,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
* [1] -- the RPC header/data, marshaled by RPC and the NFS protocol. * [1] -- the RPC header/data, marshaled by RPC and the NFS protocol.
* [2] -- optional padding. * [2] -- optional padding.
* [3] -- if padded, header only in [1] and data here. * [3] -- if padded, header only in [1] and data here.
*
* Returns zero on success, otherwise a negative errno.
*/ */
int int
...@@ -370,7 +375,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) ...@@ -370,7 +375,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
struct rpcrdma_req *req = rpcr_to_rdmar(rqst); struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
char *base; char *base;
size_t hdrlen, rpclen, padlen; size_t rpclen, padlen;
ssize_t hdrlen;
enum rpcrdma_chunktype rtype, wtype; enum rpcrdma_chunktype rtype, wtype;
struct rpcrdma_msg *headerp; struct rpcrdma_msg *headerp;
...@@ -441,14 +447,10 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) ...@@ -441,14 +447,10 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
/* The following simplification is not true forever */ /* The following simplification is not true forever */
if (rtype != rpcrdma_noch && wtype == rpcrdma_replych) if (rtype != rpcrdma_noch && wtype == rpcrdma_replych)
wtype = rpcrdma_noch; wtype = rpcrdma_noch;
BUG_ON(rtype != rpcrdma_noch && wtype != rpcrdma_noch); if (rtype != rpcrdma_noch && wtype != rpcrdma_noch) {
dprintk("RPC: %s: cannot marshal multiple chunk lists\n",
if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_BOUNCEBUFFERS && __func__);
(rtype != rpcrdma_noch || wtype != rpcrdma_noch)) { return -EIO;
/* forced to "pure inline"? */
dprintk("RPC: %s: too much data (%d/%d) for inline\n",
__func__, rqst->rq_rcv_buf.len, rqst->rq_snd_buf.len);
return -1;
} }
hdrlen = 28; /*sizeof *headerp;*/ hdrlen = 28; /*sizeof *headerp;*/
...@@ -474,8 +476,11 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) ...@@ -474,8 +476,11 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero; headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero;
headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero; headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero;
hdrlen += 2 * sizeof(u32); /* extra words in padhdr */ hdrlen += 2 * sizeof(u32); /* extra words in padhdr */
BUG_ON(wtype != rpcrdma_noch); if (wtype != rpcrdma_noch) {
dprintk("RPC: %s: invalid chunk list\n",
__func__);
return -EIO;
}
} else { } else {
headerp->rm_body.rm_nochunks.rm_empty[0] = xdr_zero; headerp->rm_body.rm_nochunks.rm_empty[0] = xdr_zero;
headerp->rm_body.rm_nochunks.rm_empty[1] = xdr_zero; headerp->rm_body.rm_nochunks.rm_empty[1] = xdr_zero;
...@@ -492,8 +497,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) ...@@ -492,8 +497,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
* on receive. Therefore, we request a reply chunk * on receive. Therefore, we request a reply chunk
* for non-writes wherever feasible and efficient. * for non-writes wherever feasible and efficient.
*/ */
if (wtype == rpcrdma_noch && if (wtype == rpcrdma_noch)
r_xprt->rx_ia.ri_memreg_strategy > RPCRDMA_REGISTER)
wtype = rpcrdma_replych; wtype = rpcrdma_replych;
} }
} }
...@@ -511,9 +515,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) ...@@ -511,9 +515,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
hdrlen = rpcrdma_create_chunks(rqst, hdrlen = rpcrdma_create_chunks(rqst,
&rqst->rq_rcv_buf, headerp, wtype); &rqst->rq_rcv_buf, headerp, wtype);
} }
if (hdrlen < 0)
if (hdrlen == 0) return hdrlen;
return -1;
dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd" dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd"
" headerp 0x%p base 0x%p lkey 0x%x\n", " headerp 0x%p base 0x%p lkey 0x%x\n",
...@@ -680,15 +683,11 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) ...@@ -680,15 +683,11 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
rqst->rq_private_buf = rqst->rq_rcv_buf; rqst->rq_private_buf = rqst->rq_rcv_buf;
} }
/*
* This function is called when an async event is posted to
* the connection which changes the connection state. All it
* does at this point is mark the connection up/down, the rpc
* timers do the rest.
*/
void void
rpcrdma_conn_func(struct rpcrdma_ep *ep) rpcrdma_connect_worker(struct work_struct *work)
{ {
struct rpcrdma_ep *ep =
container_of(work, struct rpcrdma_ep, rep_connect_worker.work);
struct rpc_xprt *xprt = ep->rep_xprt; struct rpc_xprt *xprt = ep->rep_xprt;
spin_lock_bh(&xprt->transport_lock); spin_lock_bh(&xprt->transport_lock);
...@@ -705,13 +704,15 @@ rpcrdma_conn_func(struct rpcrdma_ep *ep) ...@@ -705,13 +704,15 @@ rpcrdma_conn_func(struct rpcrdma_ep *ep)
} }
/* /*
* This function is called when memory window unbind which we are waiting * This function is called when an async event is posted to
* for completes. Just use rr_func (zeroed by upcall) to signal completion. * the connection which changes the connection state. All it
* does at this point is mark the connection up/down, the rpc
* timers do the rest.
*/ */
static void void
rpcrdma_unbind_func(struct rpcrdma_rep *rep) rpcrdma_conn_func(struct rpcrdma_ep *ep)
{ {
wake_up(&rep->rr_unbind); schedule_delayed_work(&ep->rep_connect_worker, 0);
} }
/* /*
...@@ -728,7 +729,8 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -728,7 +729,8 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
struct rpc_xprt *xprt = rep->rr_xprt; struct rpc_xprt *xprt = rep->rr_xprt;
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
__be32 *iptr; __be32 *iptr;
int i, rdmalen, status; int rdmalen, status;
unsigned long cwnd;
/* Check status. If bad, signal disconnect and return rep to pool */ /* Check status. If bad, signal disconnect and return rep to pool */
if (rep->rr_len == ~0U) { if (rep->rr_len == ~0U) {
...@@ -783,6 +785,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -783,6 +785,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
/* from here on, the reply is no longer an orphan */ /* from here on, the reply is no longer an orphan */
req->rl_reply = rep; req->rl_reply = rep;
xprt->reestablish_timeout = 0;
/* check for expected message types */ /* check for expected message types */
/* The order of some of these tests is important. */ /* The order of some of these tests is important. */
...@@ -857,26 +860,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -857,26 +860,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
break; break;
} }
/* If using mw bind, start the deregister process now. */ cwnd = xprt->cwnd;
/* (Note: if mr_free(), cannot perform it here, in tasklet context) */ xprt->cwnd = atomic_read(&r_xprt->rx_buf.rb_credits) << RPC_CWNDSHIFT;
if (req->rl_nchunks) switch (r_xprt->rx_ia.ri_memreg_strategy) { if (xprt->cwnd > cwnd)
case RPCRDMA_MEMWINDOWS: xprt_release_rqst_cong(rqst->rq_task);
for (i = 0; req->rl_nchunks-- > 1;)
i += rpcrdma_deregister_external(
&req->rl_segments[i], r_xprt, NULL);
/* Optionally wait (not here) for unbinds to complete */
rep->rr_func = rpcrdma_unbind_func;
(void) rpcrdma_deregister_external(&req->rl_segments[i],
r_xprt, rep);
break;
case RPCRDMA_MEMWINDOWS_ASYNC:
for (i = 0; req->rl_nchunks--;)
i += rpcrdma_deregister_external(&req->rl_segments[i],
r_xprt, NULL);
break;
default:
break;
}
dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n", dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",
__func__, xprt, rqst, status); __func__, xprt, rqst, status);
......
此差异已折叠。
此差异已折叠。
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/wait.h> /* wait_queue_head_t, etc */ #include <linux/wait.h> /* wait_queue_head_t, etc */
#include <linux/spinlock.h> /* spinlock_t, etc */ #include <linux/spinlock.h> /* spinlock_t, etc */
#include <linux/atomic.h> /* atomic_t, etc */ #include <linux/atomic.h> /* atomic_t, etc */
#include <linux/workqueue.h> /* struct work_struct */
#include <rdma/rdma_cm.h> /* RDMA connection api */ #include <rdma/rdma_cm.h> /* RDMA connection api */
#include <rdma/ib_verbs.h> /* RDMA verbs api */ #include <rdma/ib_verbs.h> /* RDMA verbs api */
...@@ -66,18 +67,21 @@ struct rpcrdma_ia { ...@@ -66,18 +67,21 @@ struct rpcrdma_ia {
struct completion ri_done; struct completion ri_done;
int ri_async_rc; int ri_async_rc;
enum rpcrdma_memreg ri_memreg_strategy; enum rpcrdma_memreg ri_memreg_strategy;
unsigned int ri_max_frmr_depth;
}; };
/* /*
* RDMA Endpoint -- one per transport instance * RDMA Endpoint -- one per transport instance
*/ */
#define RPCRDMA_WC_BUDGET (128)
#define RPCRDMA_POLLSIZE (16)
struct rpcrdma_ep { struct rpcrdma_ep {
atomic_t rep_cqcount; atomic_t rep_cqcount;
int rep_cqinit; int rep_cqinit;
int rep_connected; int rep_connected;
struct rpcrdma_ia *rep_ia; struct rpcrdma_ia *rep_ia;
struct ib_cq *rep_cq;
struct ib_qp_init_attr rep_attr; struct ib_qp_init_attr rep_attr;
wait_queue_head_t rep_connect_wait; wait_queue_head_t rep_connect_wait;
struct ib_sge rep_pad; /* holds zeroed pad */ struct ib_sge rep_pad; /* holds zeroed pad */
...@@ -86,6 +90,9 @@ struct rpcrdma_ep { ...@@ -86,6 +90,9 @@ struct rpcrdma_ep {
struct rpc_xprt *rep_xprt; /* for rep_func */ struct rpc_xprt *rep_xprt; /* for rep_func */
struct rdma_conn_param rep_remote_cma; struct rdma_conn_param rep_remote_cma;
struct sockaddr_storage rep_remote_addr; struct sockaddr_storage rep_remote_addr;
struct delayed_work rep_connect_worker;
struct ib_wc rep_send_wcs[RPCRDMA_POLLSIZE];
struct ib_wc rep_recv_wcs[RPCRDMA_POLLSIZE];
}; };
#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit) #define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
...@@ -124,7 +131,6 @@ struct rpcrdma_rep { ...@@ -124,7 +131,6 @@ struct rpcrdma_rep {
struct rpc_xprt *rr_xprt; /* needed for request/reply matching */ struct rpc_xprt *rr_xprt; /* needed for request/reply matching */
void (*rr_func)(struct rpcrdma_rep *);/* called by tasklet in softint */ void (*rr_func)(struct rpcrdma_rep *);/* called by tasklet in softint */
struct list_head rr_list; /* tasklet list */ struct list_head rr_list; /* tasklet list */
wait_queue_head_t rr_unbind; /* optional unbind wait */
struct ib_sge rr_iov; /* for posting */ struct ib_sge rr_iov; /* for posting */
struct ib_mr *rr_handle; /* handle for mem in rr_iov */ struct ib_mr *rr_handle; /* handle for mem in rr_iov */
char rr_base[MAX_RPCRDMAHDR]; /* minimal inline receive buffer */ char rr_base[MAX_RPCRDMAHDR]; /* minimal inline receive buffer */
...@@ -159,7 +165,6 @@ struct rpcrdma_mr_seg { /* chunk descriptors */ ...@@ -159,7 +165,6 @@ struct rpcrdma_mr_seg { /* chunk descriptors */
struct ib_mr *rl_mr; /* if registered directly */ struct ib_mr *rl_mr; /* if registered directly */
struct rpcrdma_mw { /* if registered from region */ struct rpcrdma_mw { /* if registered from region */
union { union {
struct ib_mw *mw;
struct ib_fmr *fmr; struct ib_fmr *fmr;
struct { struct {
struct ib_fast_reg_page_list *fr_pgl; struct ib_fast_reg_page_list *fr_pgl;
...@@ -207,7 +212,6 @@ struct rpcrdma_req { ...@@ -207,7 +212,6 @@ struct rpcrdma_req {
struct rpcrdma_buffer { struct rpcrdma_buffer {
spinlock_t rb_lock; /* protects indexes */ spinlock_t rb_lock; /* protects indexes */
atomic_t rb_credits; /* most recent server credits */ atomic_t rb_credits; /* most recent server credits */
unsigned long rb_cwndscale; /* cached framework rpc_cwndscale */
int rb_max_requests;/* client max requests */ int rb_max_requests;/* client max requests */
struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */
int rb_send_index; int rb_send_index;
...@@ -300,7 +304,7 @@ void rpcrdma_ia_close(struct rpcrdma_ia *); ...@@ -300,7 +304,7 @@ void rpcrdma_ia_close(struct rpcrdma_ia *);
*/ */
int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *, int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *,
struct rpcrdma_create_data_internal *); struct rpcrdma_create_data_internal *);
int rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *);
int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *);
int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *);
...@@ -330,11 +334,12 @@ int rpcrdma_deregister_internal(struct rpcrdma_ia *, ...@@ -330,11 +334,12 @@ int rpcrdma_deregister_internal(struct rpcrdma_ia *,
int rpcrdma_register_external(struct rpcrdma_mr_seg *, int rpcrdma_register_external(struct rpcrdma_mr_seg *,
int, int, struct rpcrdma_xprt *); int, int, struct rpcrdma_xprt *);
int rpcrdma_deregister_external(struct rpcrdma_mr_seg *, int rpcrdma_deregister_external(struct rpcrdma_mr_seg *,
struct rpcrdma_xprt *, void *); struct rpcrdma_xprt *);
/* /*
* RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c * RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c
*/ */
void rpcrdma_connect_worker(struct work_struct *);
void rpcrdma_conn_func(struct rpcrdma_ep *); void rpcrdma_conn_func(struct rpcrdma_ep *);
void rpcrdma_reply_handler(struct rpcrdma_rep *); void rpcrdma_reply_handler(struct rpcrdma_rep *);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册