Commit 6f83e5bd authored by Linus Torvalds's avatar Linus Torvalds

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

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

  Features:
   - Removing the forced serialisation of open()/close() calls in
     NFSv4.x (x>0) makes for a significant performance improvement in
     metadata intensive workloads.
   - Full support for the pNFS "flexible files" layout type
   - Further RPC/RDMA client improvements from Chuck

  Bugfixes:
   - Stable fix: NFSv4.1 backchannel calls blocking operations with !TASK_RUNNING
   - Stable fix: pnfs_generic_pg_init_read/write can be called with lseg == NULL
   - Stable fix: Fix an Oopsable condition when nsm_mon_unmon is called
     as part of the namespace cleanup,
   - Stable fix: Ensure we reference the inode for return-on-close in
     delegreturn
   - Use SO_REUSEPORT to ensure that NFSv3 TCP connections can rebind to
     the same source address/port combination during a disconnect/
     reconnect event.  This is a requirement imposed by most NFSv3
     server duplicate reply cache implementations.

  Optimisations:
   - Ask for no NFSv4.1 delegations on OPEN if using O_DIRECT

  Other:
   - Add Anna Schumaker as co-maintainer for the NFS client"

* tag 'nfs-for-3.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (119 commits)
  SUNRPC: Cleanup to remove xs_tcp_close()
  pnfs: delete an unintended goto
  pnfs/flexfiles: Do not dprintk after the free
  SUNRPC: Fix stupid typo in xs_sock_set_reuseport
  SUNRPC: Define xs_tcp_fin_timeout only if CONFIG_SUNRPC_DEBUG
  SUNRPC: Handle connection reset more efficiently.
  SUNRPC: Remove the redundant XPRT_CONNECTION_CLOSE flag
  SUNRPC: Make xs_tcp_close() do a socket shutdown rather than a sock_release
  SUNRPC: Ensure xs_tcp_shutdown() requests a full close of the connection
  SUNRPC: Cleanup to remove remaining uses of XPRT_CONNECTION_ABORT
  SUNRPC: Remove TCP socket linger code
  SUNRPC: Remove TCP client connection reset hack
  SUNRPC: TCP/UDP always close the old socket before reconnecting
  SUNRPC: Add helpers to prevent socket create from racing
  SUNRPC: Ensure xs_reset_transport() resets the close connection flags
  SUNRPC: Do not clear the source port in xs_reset_transport
  SUNRPC: Handle EADDRINUSE on connect
  SUNRPC: Set SO_REUSEPORT socket option for TCP connections
  NFSv4.1: Fix pnfs_put_lseg races
  NFSv4.1: pnfs_send_layoutreturn should use GFP_NOFS
  ...
parents 73b4f63a c627d31b
...@@ -57,15 +57,16 @@ bit is set, preventing any new lsegs from being added. ...@@ -57,15 +57,16 @@ bit is set, preventing any new lsegs from being added.
layout drivers layout drivers
-------------- --------------
PNFS utilizes what is called layout drivers. The STD defines 3 basic PNFS utilizes what is called layout drivers. The STD defines 4 basic
layout types: "files" "objects" and "blocks". For each of these types layout types: "files", "objects", "blocks", and "flexfiles". For each
there is a layout-driver with a common function-vectors table which of these types there is a layout-driver with a common function-vectors
are called by the nfs-client pnfs-core to implement the different layout table which are called by the nfs-client pnfs-core to implement the
types. different layout types.
Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c Files-layout-driver code is in: fs/nfs/filelayout/.. directory
Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory
Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory
Flexfiles-layout-driver code is in: fs/nfs/flexfilelayout/.. directory
objects-layout setup objects-layout setup
-------------------- --------------------
......
...@@ -6777,6 +6777,7 @@ F: Documentation/devicetree/bindings/net/nfc/ ...@@ -6777,6 +6777,7 @@ F: Documentation/devicetree/bindings/net/nfc/
NFS, SUNRPC, AND LOCKD CLIENTS NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <trond.myklebust@primarydata.com> M: Trond Myklebust <trond.myklebust@primarydata.com>
M: Anna Schumaker <anna.schumaker@netapp.com>
L: linux-nfs@vger.kernel.org L: linux-nfs@vger.kernel.org
W: http://client.linux-nfs.org W: http://client.linux-nfs.org
T: git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git T: git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git
......
...@@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) ...@@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
return (struct sockaddr *)&nsm->sm_addr; return (struct sockaddr *)&nsm->sm_addr;
} }
static struct rpc_clnt *nsm_create(struct net *net) static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
{ {
struct sockaddr_in sin = { struct sockaddr_in sin = {
.sin_family = AF_INET, .sin_family = AF_INET,
...@@ -77,6 +77,7 @@ static struct rpc_clnt *nsm_create(struct net *net) ...@@ -77,6 +77,7 @@ static struct rpc_clnt *nsm_create(struct net *net)
.address = (struct sockaddr *)&sin, .address = (struct sockaddr *)&sin,
.addrsize = sizeof(sin), .addrsize = sizeof(sin),
.servername = "rpc.statd", .servername = "rpc.statd",
.nodename = nodename,
.program = &nsm_program, .program = &nsm_program,
.version = NSM_VERSION, .version = NSM_VERSION,
.authflavor = RPC_AUTH_NULL, .authflavor = RPC_AUTH_NULL,
...@@ -102,7 +103,7 @@ static struct rpc_clnt *nsm_client_set(struct lockd_net *ln, ...@@ -102,7 +103,7 @@ static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
return clnt; return clnt;
} }
static struct rpc_clnt *nsm_client_get(struct net *net) static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
{ {
struct rpc_clnt *clnt, *new; struct rpc_clnt *clnt, *new;
struct lockd_net *ln = net_generic(net, lockd_net_id); struct lockd_net *ln = net_generic(net, lockd_net_id);
...@@ -111,7 +112,7 @@ static struct rpc_clnt *nsm_client_get(struct net *net) ...@@ -111,7 +112,7 @@ static struct rpc_clnt *nsm_client_get(struct net *net)
if (clnt != NULL) if (clnt != NULL)
goto out; goto out;
clnt = new = nsm_create(net); clnt = new = nsm_create(net, nodename);
if (IS_ERR(clnt)) if (IS_ERR(clnt))
goto out; goto out;
...@@ -190,19 +191,23 @@ int nsm_monitor(const struct nlm_host *host) ...@@ -190,19 +191,23 @@ int nsm_monitor(const struct nlm_host *host)
struct nsm_res res; struct nsm_res res;
int status; int status;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
const char *nodename = NULL;
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
if (nsm->sm_monitored) if (nsm->sm_monitored)
return 0; return 0;
if (host->h_rpcclnt)
nodename = host->h_rpcclnt->cl_nodename;
/* /*
* Choose whether to record the caller_name or IP address of * Choose whether to record the caller_name or IP address of
* this peer in the local rpc.statd's database. * this peer in the local rpc.statd's database.
*/ */
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
clnt = nsm_client_get(host->net); clnt = nsm_client_get(host->net, nodename);
if (IS_ERR(clnt)) { if (IS_ERR(clnt)) {
status = PTR_ERR(clnt); status = PTR_ERR(clnt);
dprintk("lockd: failed to create NSM upcall transport, " dprintk("lockd: failed to create NSM upcall transport, "
......
...@@ -128,6 +128,11 @@ config PNFS_OBJLAYOUT ...@@ -128,6 +128,11 @@ config PNFS_OBJLAYOUT
depends on NFS_V4_1 && SCSI_OSD_ULD depends on NFS_V4_1 && SCSI_OSD_ULD
default NFS_V4 default NFS_V4
config PNFS_FLEXFILE_LAYOUT
tristate
depends on NFS_V4_1 && NFS_V3
default m
config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
string "NFSv4.1 Implementation ID Domain" string "NFSv4.1 Implementation ID Domain"
depends on NFS_V4_1 depends on NFS_V4_1
......
...@@ -27,9 +27,10 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o ...@@ -27,9 +27,10 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o
dns_resolve.o nfs4trace.o dns_resolve.o nfs4trace.o
nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o 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 pnfs_nfs.o
nfsv4-$(CONFIG_NFS_V4_2) += nfs42proc.o nfsv4-$(CONFIG_NFS_V4_2) += nfs42proc.o
obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/ obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/
obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
obj-$(CONFIG_PNFS_BLOCK) += blocklayout/ obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
obj-$(CONFIG_PNFS_FLEXFILE_LAYOUT) += flexfilelayout/
...@@ -860,12 +860,14 @@ static const struct nfs_pageio_ops bl_pg_read_ops = { ...@@ -860,12 +860,14 @@ static const struct nfs_pageio_ops bl_pg_read_ops = {
.pg_init = bl_pg_init_read, .pg_init = bl_pg_init_read,
.pg_test = bl_pg_test_read, .pg_test = bl_pg_test_read,
.pg_doio = pnfs_generic_pg_readpages, .pg_doio = pnfs_generic_pg_readpages,
.pg_cleanup = pnfs_generic_pg_cleanup,
}; };
static const struct nfs_pageio_ops bl_pg_write_ops = { static const struct nfs_pageio_ops bl_pg_write_ops = {
.pg_init = bl_pg_init_write, .pg_init = bl_pg_init_write,
.pg_test = bl_pg_test_write, .pg_test = bl_pg_test_write,
.pg_doio = pnfs_generic_pg_writepages, .pg_doio = pnfs_generic_pg_writepages,
.pg_cleanup = pnfs_generic_pg_cleanup,
}; };
static struct pnfs_layoutdriver_type blocklayout_type = { static struct pnfs_layoutdriver_type blocklayout_type = {
......
...@@ -128,22 +128,24 @@ nfs41_callback_svc(void *vrqstp) ...@@ -128,22 +128,24 @@ nfs41_callback_svc(void *vrqstp)
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_UNINTERRUPTIBLE);
spin_lock_bh(&serv->sv_cb_lock); spin_lock_bh(&serv->sv_cb_lock);
if (!list_empty(&serv->sv_cb_list)) { if (!list_empty(&serv->sv_cb_list)) {
req = list_first_entry(&serv->sv_cb_list, req = list_first_entry(&serv->sv_cb_list,
struct rpc_rqst, rq_bc_list); struct rpc_rqst, rq_bc_list);
list_del(&req->rq_bc_list); list_del(&req->rq_bc_list);
spin_unlock_bh(&serv->sv_cb_lock); spin_unlock_bh(&serv->sv_cb_lock);
finish_wait(&serv->sv_cb_waitq, &wq);
dprintk("Invoking bc_svc_process()\n"); dprintk("Invoking bc_svc_process()\n");
error = bc_svc_process(serv, req, rqstp); error = bc_svc_process(serv, req, rqstp);
dprintk("bc_svc_process() returned w/ error code= %d\n", dprintk("bc_svc_process() returned w/ error code= %d\n",
error); error);
} else { } else {
spin_unlock_bh(&serv->sv_cb_lock); spin_unlock_bh(&serv->sv_cb_lock);
schedule(); /* schedule_timeout to game the hung task watchdog */
schedule_timeout(60 * HZ);
finish_wait(&serv->sv_cb_waitq, &wq);
} }
finish_wait(&serv->sv_cb_waitq, &wq);
} }
return 0; return 0;
} }
......
...@@ -306,6 +306,17 @@ nfs_inode_detach_delegation(struct inode *inode) ...@@ -306,6 +306,17 @@ nfs_inode_detach_delegation(struct inode *inode)
return nfs_detach_delegation(nfsi, delegation, server); return nfs_detach_delegation(nfsi, delegation, server);
} }
static void
nfs_update_inplace_delegation(struct nfs_delegation *delegation,
const struct nfs_delegation *update)
{
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
delegation->stateid.seqid = update->stateid.seqid;
smp_wmb();
delegation->type = update->type;
}
}
/** /**
* nfs_inode_set_delegation - set up a delegation on an inode * nfs_inode_set_delegation - set up a delegation on an inode
* @inode: inode to which delegation applies * @inode: inode to which delegation applies
...@@ -339,9 +350,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct ...@@ -339,9 +350,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
old_delegation = rcu_dereference_protected(nfsi->delegation, old_delegation = rcu_dereference_protected(nfsi->delegation,
lockdep_is_held(&clp->cl_lock)); lockdep_is_held(&clp->cl_lock));
if (old_delegation != NULL) { if (old_delegation != NULL) {
if (nfs4_stateid_match(&delegation->stateid, /* Is this an update of the existing delegation? */
&old_delegation->stateid) && if (nfs4_stateid_match_other(&old_delegation->stateid,
delegation->type == old_delegation->type) { &delegation->stateid)) {
nfs_update_inplace_delegation(old_delegation,
delegation);
nfsi->delegation_state = old_delegation->type;
goto out; goto out;
} }
/* /*
......
...@@ -66,6 +66,10 @@ static struct kmem_cache *nfs_direct_cachep; ...@@ -66,6 +66,10 @@ static struct kmem_cache *nfs_direct_cachep;
/* /*
* This represents a set of asynchronous requests that we're waiting on * This represents a set of asynchronous requests that we're waiting on
*/ */
struct nfs_direct_mirror {
ssize_t count;
};
struct nfs_direct_req { struct nfs_direct_req {
struct kref kref; /* release manager */ struct kref kref; /* release manager */
...@@ -78,8 +82,13 @@ struct nfs_direct_req { ...@@ -78,8 +82,13 @@ struct nfs_direct_req {
/* completion state */ /* completion state */
atomic_t io_count; /* i/os we're waiting for */ atomic_t io_count; /* i/os we're waiting for */
spinlock_t lock; /* protect completion state */ spinlock_t lock; /* protect completion state */
struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX];
int mirror_count;
ssize_t count, /* bytes actually processed */ ssize_t count, /* bytes actually processed */
bytes_left, /* bytes left to be sent */ bytes_left, /* bytes left to be sent */
io_start, /* start of IO */
error; /* any reported error */ error; /* any reported error */
struct completion completion; /* wait for i/o completion */ struct completion completion; /* wait for i/o completion */
...@@ -108,26 +117,56 @@ static inline int put_dreq(struct nfs_direct_req *dreq) ...@@ -108,26 +117,56 @@ 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);
} }
void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq)
{
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
}
EXPORT_SYMBOL_GPL(nfs_direct_set_resched_writes);
static void
nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr)
{
int i;
ssize_t count;
WARN_ON_ONCE(hdr->pgio_mirror_idx >= dreq->mirror_count);
count = dreq->mirrors[hdr->pgio_mirror_idx].count;
if (count + dreq->io_start < hdr->io_start + hdr->good_bytes) {
count = hdr->io_start + hdr->good_bytes - dreq->io_start;
dreq->mirrors[hdr->pgio_mirror_idx].count = count;
}
/* update the dreq->count by finding the minimum agreed count from all
* mirrors */
count = dreq->mirrors[0].count;
for (i = 1; i < dreq->mirror_count; i++)
count = min(count, dreq->mirrors[i].count);
dreq->count = count;
}
/* /*
* nfs_direct_select_verf - select the right verifier * nfs_direct_select_verf - select the right verifier
* @dreq - direct request possibly spanning multiple servers * @dreq - direct request possibly spanning multiple servers
* @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs * @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 * @commit_idx - commit bucket index for the DS
* *
* returns the correct verifier to use given the role of the server * returns the correct verifier to use given the role of the server
*/ */
static struct nfs_writeverf * static struct nfs_writeverf *
nfs_direct_select_verf(struct nfs_direct_req *dreq, nfs_direct_select_verf(struct nfs_direct_req *dreq,
struct nfs_client *ds_clp, struct nfs_client *ds_clp,
int ds_idx) int commit_idx)
{ {
struct nfs_writeverf *verfp = &dreq->verf; struct nfs_writeverf *verfp = &dreq->verf;
#ifdef CONFIG_NFS_V4_1 #ifdef CONFIG_NFS_V4_1
if (ds_clp) { if (ds_clp) {
/* pNFS is in use, use the DS verf */ /* pNFS is in use, use the DS verf */
if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets) if (commit_idx >= 0 && commit_idx < dreq->ds_cinfo.nbuckets)
verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf; verfp = &dreq->ds_cinfo.buckets[commit_idx].direct_verf;
else else
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
} }
...@@ -148,8 +187,7 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, ...@@ -148,8 +187,7 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
{ {
struct nfs_writeverf *verfp; struct nfs_writeverf *verfp;
verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx);
hdr->ds_idx);
WARN_ON_ONCE(verfp->committed >= 0); WARN_ON_ONCE(verfp->committed >= 0);
memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
WARN_ON_ONCE(verfp->committed < 0); WARN_ON_ONCE(verfp->committed < 0);
...@@ -169,8 +207,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, ...@@ -169,8 +207,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
{ {
struct nfs_writeverf *verfp; struct nfs_writeverf *verfp;
verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx);
hdr->ds_idx);
if (verfp->committed < 0) { if (verfp->committed < 0) {
nfs_direct_set_hdr_verf(dreq, hdr); nfs_direct_set_hdr_verf(dreq, hdr);
return 0; return 0;
...@@ -193,7 +230,11 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, ...@@ -193,7 +230,11 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
verfp = nfs_direct_select_verf(dreq, data->ds_clp, verfp = nfs_direct_select_verf(dreq, data->ds_clp,
data->ds_commit_index); data->ds_commit_index);
WARN_ON_ONCE(verfp->committed < 0);
/* verifier not set so always fail */
if (verfp->committed < 0)
return 1;
return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
} }
...@@ -249,6 +290,18 @@ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, ...@@ -249,6 +290,18 @@ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
cinfo->completion_ops = &nfs_direct_commit_completion_ops; cinfo->completion_ops = &nfs_direct_commit_completion_ops;
} }
static inline void nfs_direct_setup_mirroring(struct nfs_direct_req *dreq,
struct nfs_pageio_descriptor *pgio,
struct nfs_page *req)
{
int mirror_count = 1;
if (pgio->pg_ops->pg_get_mirror_count)
mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
dreq->mirror_count = mirror_count;
}
static inline struct nfs_direct_req *nfs_direct_req_alloc(void) static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
{ {
struct nfs_direct_req *dreq; struct nfs_direct_req *dreq;
...@@ -263,6 +316,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) ...@@ -263,6 +316,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
INIT_LIST_HEAD(&dreq->mds_cinfo.list); INIT_LIST_HEAD(&dreq->mds_cinfo.list);
dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ 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);
dreq->mirror_count = 1;
spin_lock_init(&dreq->lock); spin_lock_init(&dreq->lock);
return dreq; return dreq;
...@@ -369,7 +423,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) ...@@ -369,7 +423,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0)) if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0))
dreq->error = hdr->error; dreq->error = hdr->error;
else else
dreq->count += hdr->good_bytes; nfs_direct_good_bytes(dreq, hdr);
spin_unlock(&dreq->lock); spin_unlock(&dreq->lock);
while (!list_empty(&hdr->pages)) { while (!list_empty(&hdr->pages)) {
...@@ -547,6 +602,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, ...@@ -547,6 +602,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
dreq->inode = inode; dreq->inode = inode;
dreq->bytes_left = count; dreq->bytes_left = count;
dreq->io_start = pos;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx); l_ctx = nfs_get_lock_context(dreq->ctx);
if (IS_ERR(l_ctx)) { if (IS_ERR(l_ctx)) {
...@@ -579,6 +635,20 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, ...@@ -579,6 +635,20 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
return result; return result;
} }
static void
nfs_direct_write_scan_commit_list(struct inode *inode,
struct list_head *list,
struct nfs_commit_info *cinfo)
{
spin_lock(cinfo->lock);
#ifdef CONFIG_NFS_V4_1
if (cinfo->ds != NULL && cinfo->ds->nwritten != 0)
NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo);
#endif
nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0);
spin_unlock(cinfo->lock);
}
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
{ {
struct nfs_pageio_descriptor desc; struct nfs_pageio_descriptor desc;
...@@ -586,20 +656,23 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) ...@@ -586,20 +656,23 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
LIST_HEAD(reqs); LIST_HEAD(reqs);
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
LIST_HEAD(failed); LIST_HEAD(failed);
int i;
nfs_init_cinfo_from_dreq(&cinfo, dreq); nfs_init_cinfo_from_dreq(&cinfo, dreq);
pnfs_recover_commit_reqs(dreq->inode, &reqs, &cinfo); nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
spin_lock(cinfo.lock);
nfs_scan_commit_list(&cinfo.mds->list, &reqs, &cinfo, 0);
spin_unlock(cinfo.lock);
dreq->count = 0; dreq->count = 0;
for (i = 0; i < dreq->mirror_count; i++)
dreq->mirrors[i].count = 0;
get_dreq(dreq); get_dreq(dreq);
nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, 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;
req = nfs_list_entry(reqs.next);
nfs_direct_setup_mirroring(dreq, &desc, req);
list_for_each_entry_safe(req, tmp, &reqs, wb_list) { list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
if (!nfs_pageio_add_request(&desc, req)) { if (!nfs_pageio_add_request(&desc, req)) {
nfs_list_remove_request(req); nfs_list_remove_request(req);
...@@ -646,7 +719,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) ...@@ -646,7 +719,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
nfs_list_remove_request(req); nfs_list_remove_request(req);
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) { if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) {
/* Note the rewrite will go through mds */ /* Note the rewrite will go through mds */
nfs_mark_request_commit(req, NULL, &cinfo); nfs_mark_request_commit(req, NULL, &cinfo, 0);
} else } else
nfs_release_request(req); nfs_release_request(req);
nfs_unlock_and_release_request(req); nfs_unlock_and_release_request(req);
...@@ -721,7 +794,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) ...@@ -721,7 +794,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
dreq->error = hdr->error; dreq->error = hdr->error;
} }
if (dreq->error == 0) { if (dreq->error == 0) {
dreq->count += hdr->good_bytes; nfs_direct_good_bytes(dreq, hdr);
if (nfs_write_need_commit(hdr)) { if (nfs_write_need_commit(hdr)) {
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
request_commit = true; request_commit = true;
...@@ -745,7 +818,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) ...@@ -745,7 +818,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
nfs_list_remove_request(req); nfs_list_remove_request(req);
if (request_commit) { if (request_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,
hdr->ds_commit_idx);
} }
nfs_unlock_and_release_request(req); nfs_unlock_and_release_request(req);
} }
...@@ -826,6 +900,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -826,6 +900,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
result = PTR_ERR(req); result = PTR_ERR(req);
break; break;
} }
nfs_direct_setup_mirroring(dreq, &desc, req);
nfs_lock_request(req); nfs_lock_request(req);
req->wb_index = pos >> PAGE_SHIFT; req->wb_index = pos >> PAGE_SHIFT;
req->wb_offset = pos & ~PAGE_MASK; req->wb_offset = pos & ~PAGE_MASK;
...@@ -934,6 +1011,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -934,6 +1011,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
dreq->inode = inode; dreq->inode = inode;
dreq->bytes_left = count; dreq->bytes_left = count;
dreq->io_start = pos;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx); l_ctx = nfs_get_lock_context(dreq->ctx);
if (IS_ERR(l_ctx)) { if (IS_ERR(l_ctx)) {
......
This diff is collapsed.
...@@ -32,13 +32,6 @@ ...@@ -32,13 +32,6 @@
#include "../pnfs.h" #include "../pnfs.h"
/*
* Default data server connection timeout and retrans vaules.
* Set by module paramters dataserver_timeo and dataserver_retrans.
*/
#define NFS4_DEF_DS_TIMEO 600 /* in tenths of a second */
#define NFS4_DEF_DS_RETRANS 5
/* /*
* Field testing shows we need to support up to 4096 stripe indices. * Field testing shows we need to support up to 4096 stripe indices.
* We store each index as a u8 (u32 on the wire) to keep the memory footprint * We store each index as a u8 (u32 on the wire) to keep the memory footprint
...@@ -48,32 +41,11 @@ ...@@ -48,32 +41,11 @@
#define NFS4_PNFS_MAX_STRIPE_CNT 4096 #define NFS4_PNFS_MAX_STRIPE_CNT 4096
#define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */ #define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */
/* error codes for internal use */
#define NFS4ERR_RESET_TO_MDS 12001
enum stripetype4 { enum stripetype4 {
STRIPE_SPARSE = 1, STRIPE_SPARSE = 1,
STRIPE_DENSE = 2 STRIPE_DENSE = 2
}; };
/* Individual ip address */
struct nfs4_pnfs_ds_addr {
struct sockaddr_storage da_addr;
size_t da_addrlen;
struct list_head da_node; /* nfs4_pnfs_dev_hlist dev_dslist */
char *da_remotestr; /* human readable addr+port */
};
struct nfs4_pnfs_ds {
struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */
char *ds_remotestr; /* comma sep list of addrs */
struct list_head ds_addrs;
struct nfs_client *ds_clp;
atomic_t ds_count;
unsigned long ds_state;
#define NFS4DS_CONNECTING 0 /* ds is establishing connection */
};
struct nfs4_file_layout_dsaddr { struct nfs4_file_layout_dsaddr {
struct nfs4_deviceid_node id_node; struct nfs4_deviceid_node id_node;
u32 stripe_count; u32 stripe_count;
...@@ -119,17 +91,6 @@ FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg) ...@@ -119,17 +91,6 @@ FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg)
return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node; return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node;
} }
static inline void
filelayout_mark_devid_invalid(struct nfs4_deviceid_node *node)
{
u32 *p = (u32 *)&node->deviceid;
printk(KERN_WARNING "NFS: Deviceid [%x%x%x%x] marked out of use.\n",
p[0], p[1], p[2], p[3]);
set_bit(NFS_DEVICEID_INVALID, &node->flags);
}
static inline bool static inline bool
filelayout_test_devid_invalid(struct nfs4_deviceid_node *node) filelayout_test_devid_invalid(struct nfs4_deviceid_node *node)
{ {
...@@ -142,7 +103,6 @@ filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node); ...@@ -142,7 +103,6 @@ filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node);
extern struct nfs_fh * extern struct nfs_fh *
nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
extern void print_ds(struct nfs4_pnfs_ds *ds);
u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset); u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset);
u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j); u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j);
struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
......
This diff is collapsed.
#
# Makefile for the pNFS Flexfile Layout Driver kernel module
#
obj-$(CONFIG_PNFS_FLEXFILE_LAYOUT) += nfs_layout_flexfiles.o
nfs_layout_flexfiles-y := flexfilelayout.o flexfilelayoutdev.o
This diff is collapsed.
/*
* NFSv4 flexfile layout driver data structures.
*
* Copyright (c) 2014, Primary Data, Inc. All rights reserved.
*
* Tao Peng <bergwolf@primarydata.com>
*/
#ifndef FS_NFS_NFS4FLEXFILELAYOUT_H
#define FS_NFS_NFS4FLEXFILELAYOUT_H
#include "../pnfs.h"
/* XXX: Let's filter out insanely large mirror count for now to avoid oom
* due to network error etc. */
#define NFS4_FLEXFILE_LAYOUT_MAX_MIRROR_CNT 4096
struct nfs4_ff_ds_version {
u32 version;
u32 minor_version;
u32 rsize;
u32 wsize;
bool tightly_coupled;
};
/* chained in global deviceid hlist */
struct nfs4_ff_layout_ds {
struct nfs4_deviceid_node id_node;
u32 ds_versions_cnt;
struct nfs4_ff_ds_version *ds_versions;
struct nfs4_pnfs_ds *ds;
};
struct nfs4_ff_layout_ds_err {
struct list_head list; /* linked in mirror error_list */
u64 offset;
u64 length;
int status;
enum nfs_opnum4 opnum;
nfs4_stateid stateid;
struct nfs4_deviceid deviceid;
};
struct nfs4_ff_layout_mirror {
u32 ds_count;
u32 efficiency;
struct nfs4_ff_layout_ds *mirror_ds;
u32 fh_versions_cnt;
struct nfs_fh *fh_versions;
nfs4_stateid stateid;
struct nfs4_string user_name;
struct nfs4_string group_name;
u32 uid;
u32 gid;
struct rpc_cred *cred;
spinlock_t lock;
};
struct nfs4_ff_layout_segment {
struct pnfs_layout_segment generic_hdr;
u64 stripe_unit;
u32 mirror_array_cnt;
struct nfs4_ff_layout_mirror **mirror_array;
};
struct nfs4_flexfile_layout {
struct pnfs_layout_hdr generic_hdr;
struct pnfs_ds_commit_info commit_info;
struct list_head error_list; /* nfs4_ff_layout_ds_err */
};
static inline struct nfs4_flexfile_layout *
FF_LAYOUT_FROM_HDR(struct pnfs_layout_hdr *lo)
{
return container_of(lo, struct nfs4_flexfile_layout, generic_hdr);
}
static inline struct nfs4_ff_layout_segment *
FF_LAYOUT_LSEG(struct pnfs_layout_segment *lseg)
{
return container_of(lseg,
struct nfs4_ff_layout_segment,
generic_hdr);
}
static inline struct nfs4_deviceid_node *
FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx)
{
if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt ||
FF_LAYOUT_LSEG(lseg)->mirror_array[idx] == NULL ||
FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds == NULL)
return NULL;
return &FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds->id_node;
}
static inline struct nfs4_ff_layout_ds *
FF_LAYOUT_MIRROR_DS(struct nfs4_deviceid_node *node)
{
return container_of(node, struct nfs4_ff_layout_ds, id_node);
}
static inline struct nfs4_ff_layout_mirror *
FF_LAYOUT_COMP(struct pnfs_layout_segment *lseg, u32 idx)
{
if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt)
return NULL;
return FF_LAYOUT_LSEG(lseg)->mirror_array[idx];
}
static inline u32
FF_LAYOUT_MIRROR_COUNT(struct pnfs_layout_segment *lseg)
{
return FF_LAYOUT_LSEG(lseg)->mirror_array_cnt;
}
static inline bool
ff_layout_test_devid_unavailable(struct nfs4_deviceid_node *node)
{
return nfs4_test_deviceid_unavailable(node);
}
static inline int
nfs4_ff_layout_ds_version(struct pnfs_layout_segment *lseg, u32 ds_idx)
{
return FF_LAYOUT_COMP(lseg, ds_idx)->mirror_ds->ds_versions[0].version;
}
struct nfs4_ff_layout_ds *
nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
gfp_t gfp_flags);
void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds);
void nfs4_ff_layout_free_deviceid(struct nfs4_ff_layout_ds *mirror_ds);
int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
struct nfs4_ff_layout_mirror *mirror, u64 offset,
u64 length, int status, enum nfs_opnum4 opnum,
gfp_t gfp_flags);
int ff_layout_encode_ds_ioerr(struct nfs4_flexfile_layout *flo,
struct xdr_stream *xdr, int *count,
const struct pnfs_layout_range *range);
struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx);
struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
bool fail_return);
struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct pnfs_layout_segment *lseg,
u32 ds_idx,
struct nfs_client *ds_clp,
struct inode *inode);
struct rpc_cred *ff_layout_get_ds_cred(struct pnfs_layout_segment *lseg,
u32 ds_idx, struct rpc_cred *mdscred);
bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg);
#endif /* FS_NFS_NFS4FLEXFILELAYOUT_H */
This diff is collapsed.
...@@ -152,7 +152,7 @@ void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *f ...@@ -152,7 +152,7 @@ void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *f
nfs_fattr_free_group_name(fattr); nfs_fattr_free_group_name(fattr);
} }
static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res) int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
{ {
unsigned long val; unsigned long val;
char buf[16]; char buf[16];
...@@ -166,6 +166,7 @@ static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *re ...@@ -166,6 +166,7 @@ static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *re
*res = val; *res = val;
return 1; return 1;
} }
EXPORT_SYMBOL_GPL(nfs_map_string_to_numeric);
static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
{ {
......
...@@ -507,10 +507,15 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -507,10 +507,15 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~ATTR_MODE; attr->ia_valid &= ~ATTR_MODE;
if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_valid & ATTR_SIZE) {
loff_t i_size;
BUG_ON(!S_ISREG(inode->i_mode)); BUG_ON(!S_ISREG(inode->i_mode));
if (attr->ia_size == i_size_read(inode)) i_size = i_size_read(inode);
if (attr->ia_size == i_size)
attr->ia_valid &= ~ATTR_SIZE; attr->ia_valid &= ~ATTR_SIZE;
else if (attr->ia_size < i_size && IS_SWAPFILE(inode))
return -ETXTBSY;
} }
/* Optimization: if the end result is no change, don't RPC */ /* Optimization: if the end result is no change, don't RPC */
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/nfs_page.h>
#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
...@@ -187,9 +188,15 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, ...@@ -187,9 +188,15 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
const struct sockaddr *ds_addr, const struct sockaddr *ds_addr,
int ds_addrlen, int ds_proto, int ds_addrlen, int ds_proto,
unsigned int ds_timeo, unsigned int ds_timeo,
unsigned int ds_retrans); unsigned int ds_retrans,
u32 minor_version,
rpc_authflavor_t au_flavor);
extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *, extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *,
struct inode *); struct inode *);
extern struct nfs_client *nfs3_set_ds_client(struct nfs_client *mds_clp,
const struct sockaddr *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo,
unsigned int ds_retrans, rpc_authflavor_t au_flavor);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void); extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void); extern void nfs_fs_proc_exit(void);
...@@ -242,9 +249,12 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); ...@@ -242,9 +249,12 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
void nfs_pgio_header_free(struct nfs_pgio_header *); void nfs_pgio_header_free(struct nfs_pgio_header *);
void nfs_pgio_data_destroy(struct nfs_pgio_header *); void nfs_pgio_data_destroy(struct nfs_pgio_header *);
int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_header *, int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
const struct rpc_call_ops *, int, int); struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
const struct rpc_call_ops *call_ops, int how, int flags);
void nfs_free_request(struct nfs_page *req); void nfs_free_request(struct nfs_page *req);
struct nfs_pgio_mirror *
nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc);
static inline void nfs_iocounter_init(struct nfs_io_counter *c) static inline void nfs_iocounter_init(struct nfs_io_counter *c)
{ {
...@@ -252,6 +262,12 @@ static inline void nfs_iocounter_init(struct nfs_io_counter *c) ...@@ -252,6 +262,12 @@ static inline void nfs_iocounter_init(struct nfs_io_counter *c)
atomic_set(&c->io_count, 0); atomic_set(&c->io_count, 0);
} }
static inline bool nfs_pgio_has_mirroring(struct nfs_pageio_descriptor *desc)
{
WARN_ON_ONCE(desc->pg_mirror_count < 1);
return desc->pg_mirror_count > 1;
}
/* nfs2xdr.c */ /* nfs2xdr.c */
extern struct rpc_procinfo nfs_procedures[]; extern struct rpc_procinfo nfs_procedures[];
extern int nfs2_decode_dirent(struct xdr_stream *, extern int nfs2_decode_dirent(struct xdr_stream *,
...@@ -375,7 +391,7 @@ extern struct rpc_stat nfs_rpcstat; ...@@ -375,7 +391,7 @@ extern struct rpc_stat nfs_rpcstat;
extern int __init register_nfs_fs(void); extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void); extern void __exit unregister_nfs_fs(void);
extern void nfs_sb_active(struct super_block *sb); extern bool nfs_sb_active(struct super_block *sb);
extern void nfs_sb_deactive(struct super_block *sb); extern void nfs_sb_deactive(struct super_block *sb);
/* namespace.c */ /* namespace.c */
...@@ -427,6 +443,7 @@ extern void nfs_write_prepare(struct rpc_task *task, void *calldata); ...@@ -427,6 +443,7 @@ 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,
struct nfs_commit_data *data, struct nfs_commit_data *data,
const struct nfs_rpc_ops *nfs_ops,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
int how, int flags); int how, int flags);
extern void nfs_init_commit(struct nfs_commit_data *data, extern void nfs_init_commit(struct nfs_commit_data *data,
...@@ -440,13 +457,15 @@ int nfs_scan_commit(struct inode *inode, struct list_head *dst, ...@@ -440,13 +457,15 @@ 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,
struct pnfs_layout_segment *lseg, struct pnfs_layout_segment *lseg,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo,
u32 ds_commit_idx);
int nfs_write_need_commit(struct nfs_pgio_header *); int nfs_write_need_commit(struct nfs_pgio_header *);
int nfs_generic_commit_list(struct inode *inode, struct list_head *head, int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
int how, struct nfs_commit_info *cinfo); int how, struct nfs_commit_info *cinfo);
void nfs_retry_commit(struct list_head *page_list, void nfs_retry_commit(struct list_head *page_list,
struct pnfs_layout_segment *lseg, struct pnfs_layout_segment *lseg,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo,
u32 ds_commit_idx);
void nfs_commitdata_release(struct nfs_commit_data *data); void nfs_commitdata_release(struct nfs_commit_data *data);
void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst, void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo);
...@@ -457,6 +476,7 @@ void nfs_init_cinfo(struct nfs_commit_info *cinfo, ...@@ -457,6 +476,7 @@ void nfs_init_cinfo(struct nfs_commit_info *cinfo,
struct nfs_direct_req *dreq); struct nfs_direct_req *dreq);
int nfs_key_timeout_notify(struct file *filp, struct inode *inode); int nfs_key_timeout_notify(struct file *filp, struct inode *inode);
bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx); bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx);
void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio);
#ifdef CONFIG_MIGRATION #ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *, extern int nfs_migrate_page(struct address_space *,
...@@ -480,6 +500,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode) ...@@ -480,6 +500,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode)
inode_dio_wait(inode); inode_dio_wait(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);
extern void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq);
/* nfs4proc.c */ /* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_pgio_header *); extern void __nfs4_read_done_cb(struct nfs_pgio_header *);
...@@ -493,6 +514,26 @@ extern int nfs41_walk_client_list(struct nfs_client *clp, ...@@ -493,6 +514,26 @@ extern int nfs41_walk_client_list(struct nfs_client *clp,
struct nfs_client **result, struct nfs_client **result,
struct rpc_cred *cred); struct rpc_cred *cred);
static inline struct inode *nfs_igrab_and_active(struct inode *inode)
{
inode = igrab(inode);
if (inode != NULL && !nfs_sb_active(inode->i_sb)) {
iput(inode);
inode = NULL;
}
return inode;
}
static inline void nfs_iput_and_deactive(struct inode *inode)
{
if (inode != NULL) {
struct super_block *sb = inode->i_sb;
iput(inode);
nfs_sb_deactive(sb);
}
}
/* /*
* Determine the device name as a string * Determine the device name as a string
*/ */
......
...@@ -481,7 +481,8 @@ static int decode_path(struct xdr_stream *xdr) ...@@ -481,7 +481,8 @@ static int decode_path(struct xdr_stream *xdr)
* void; * void;
* }; * };
*/ */
static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result) static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
__u32 *op_status)
{ {
enum nfs_stat status; enum nfs_stat status;
int error; int error;
...@@ -489,6 +490,8 @@ static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result) ...@@ -489,6 +490,8 @@ static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
error = decode_stat(xdr, &status); error = decode_stat(xdr, &status);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
if (op_status)
*op_status = status;
if (status != NFS_OK) if (status != NFS_OK)
goto out_default; goto out_default;
error = decode_fattr(xdr, result); error = decode_fattr(xdr, result);
...@@ -808,7 +811,7 @@ static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -808,7 +811,7 @@ static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
struct nfs_fattr *result) struct nfs_fattr *result)
{ {
return decode_attrstat(xdr, result); return decode_attrstat(xdr, result, NULL);
} }
static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
...@@ -865,6 +868,7 @@ static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -865,6 +868,7 @@ static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
error = decode_stat(xdr, &status); error = decode_stat(xdr, &status);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
result->op_status = status;
if (status != NFS_OK) if (status != NFS_OK)
goto out_default; goto out_default;
error = decode_fattr(xdr, result->fattr); error = decode_fattr(xdr, result->fattr);
...@@ -882,7 +886,7 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -882,7 +886,7 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
{ {
/* 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;
return decode_attrstat(xdr, result->fattr); return decode_attrstat(xdr, result->fattr, &result->op_status);
} }
/** /**
......
...@@ -30,5 +30,7 @@ struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subver ...@@ -30,5 +30,7 @@ struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subver
struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *, struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t); struct nfs_fattr *, rpc_authflavor_t);
/* nfs3super.c */
extern struct nfs_subversion nfs_v3;
#endif /* __LINUX_FS_NFS_NFS3_FS_H */ #endif /* __LINUX_FS_NFS_NFS3_FS_H */
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_mount.h> #include <linux/nfs_mount.h>
#include <linux/sunrpc/addr.h>
#include "internal.h" #include "internal.h"
#include "nfs3_fs.h" #include "nfs3_fs.h"
...@@ -64,3 +65,43 @@ struct nfs_server *nfs3_clone_server(struct nfs_server *source, ...@@ -64,3 +65,43 @@ struct nfs_server *nfs3_clone_server(struct nfs_server *source,
nfs_init_server_aclclient(server); nfs_init_server_aclclient(server);
return server; return server;
} }
/*
* Set up a pNFS Data Server client over NFSv3.
*
* Return any existing nfs_client that matches server address,port,version
* and minorversion.
*
* For a new nfs_client, use a soft mount (default), a low retrans and a
* low timeout interval so that if a connection is lost, we retry through
* the MDS.
*/
struct nfs_client *nfs3_set_ds_client(struct nfs_client *mds_clp,
const struct sockaddr *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
rpc_authflavor_t au_flavor)
{
struct nfs_client_initdata cl_init = {
.addr = ds_addr,
.addrlen = ds_addrlen,
.nfs_mod = &nfs_v3,
.proto = ds_proto,
.net = mds_clp->cl_net,
};
struct rpc_timeout ds_timeout;
struct nfs_client *clp;
char buf[INET6_ADDRSTRLEN + 1];
/* fake a hostname because lockd wants it */
if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0)
return ERR_PTR(-EINVAL);
cl_init.hostname = buf;
/* Use the MDS nfs_client cl_ipaddr. */
nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
au_flavor);
return clp;
}
EXPORT_SYMBOL_GPL(nfs3_set_ds_client);
...@@ -800,6 +800,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) ...@@ -800,6 +800,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
{ {
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
if (hdr->pgio_done_cb != NULL)
return hdr->pgio_done_cb(task, hdr);
if (nfs3_async_handle_jukebox(task, inode)) if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
...@@ -825,6 +828,9 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) ...@@ -825,6 +828,9 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
{ {
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
if (hdr->pgio_done_cb != NULL)
return hdr->pgio_done_cb(task, hdr);
if (nfs3_async_handle_jukebox(task, inode)) if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) if (task->tk_status >= 0)
...@@ -845,6 +851,9 @@ static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commi ...@@ -845,6 +851,9 @@ static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commi
static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data) static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
{ {
if (data->commit_done_cb != NULL)
return data->commit_done_cb(task, data);
if (nfs3_async_handle_jukebox(task, data->inode)) if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN; return -EAGAIN;
nfs_refresh_inode(data->inode, data->res.fattr); nfs_refresh_inode(data->inode, data->res.fattr);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "nfs3_fs.h" #include "nfs3_fs.h"
#include "nfs.h" #include "nfs.h"
static struct nfs_subversion nfs_v3 = { struct nfs_subversion nfs_v3 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nfs_fs = &nfs_fs_type, .nfs_fs = &nfs_fs_type,
.rpc_vers = &nfs_version3, .rpc_vers = &nfs_version3,
......
...@@ -1636,6 +1636,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1636,6 +1636,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
error = decode_post_op_attr(xdr, result->fattr); error = decode_post_op_attr(xdr, result->fattr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
result->op_status = status;
if (status != NFS3_OK) if (status != NFS3_OK)
goto out_status; goto out_status;
error = decode_read3resok(xdr, result); error = decode_read3resok(xdr, result);
...@@ -1708,6 +1709,7 @@ static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1708,6 +1709,7 @@ static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
error = decode_wcc_data(xdr, result->fattr); error = decode_wcc_data(xdr, result->fattr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
result->op_status = status;
if (status != NFS3_OK) if (status != NFS3_OK)
goto out_status; goto out_status;
error = decode_write3resok(xdr, result); error = decode_write3resok(xdr, result);
...@@ -2323,6 +2325,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, ...@@ -2323,6 +2325,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
error = decode_wcc_data(xdr, result->fattr); error = decode_wcc_data(xdr, result->fattr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
result->op_status = status;
if (status != NFS3_OK) if (status != NFS3_OK)
goto out_status; goto out_status;
error = decode_writeverf3(xdr, &result->verf->verifier); error = decode_writeverf3(xdr, &result->verf->verifier);
......
...@@ -44,6 +44,7 @@ enum nfs4_client_state { ...@@ -44,6 +44,7 @@ enum nfs4_client_state {
#define NFS4_RENEW_TIMEOUT 0x01 #define NFS4_RENEW_TIMEOUT 0x01
#define NFS4_RENEW_DELEGATION_CB 0x02 #define NFS4_RENEW_DELEGATION_CB 0x02
struct nfs_seqid_counter;
struct nfs4_minor_version_ops { struct nfs4_minor_version_ops {
u32 minor_version; u32 minor_version;
unsigned init_caps; unsigned init_caps;
...@@ -56,6 +57,8 @@ struct nfs4_minor_version_ops { ...@@ -56,6 +57,8 @@ struct nfs4_minor_version_ops {
struct nfs_fsinfo *); struct nfs_fsinfo *);
void (*free_lock_state)(struct nfs_server *, void (*free_lock_state)(struct nfs_server *,
struct nfs4_lock_state *); struct nfs4_lock_state *);
struct nfs_seqid *
(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
const struct rpc_call_ops *call_sync_ops; const struct rpc_call_ops *call_sync_ops;
const struct nfs4_state_recovery_ops *reboot_recovery_ops; const struct nfs4_state_recovery_ops *reboot_recovery_ops;
const struct nfs4_state_recovery_ops *nograce_recovery_ops; const struct nfs4_state_recovery_ops *nograce_recovery_ops;
...@@ -443,6 +446,12 @@ extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); ...@@ -443,6 +446,12 @@ extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_release_seqid(struct nfs_seqid *seqid); extern void nfs_release_seqid(struct nfs_seqid *seqid);
extern void nfs_free_seqid(struct nfs_seqid *seqid); extern void nfs_free_seqid(struct nfs_seqid *seqid);
extern int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
struct rpc_task *task);
extern int nfs4_sequence_done(struct rpc_task *task,
struct nfs4_sequence_res *res);
extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp); extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp);
......
...@@ -849,14 +849,15 @@ static int nfs4_set_client(struct nfs_server *server, ...@@ -849,14 +849,15 @@ static int nfs4_set_client(struct nfs_server *server,
*/ */
struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
const struct sockaddr *ds_addr, int ds_addrlen, const struct sockaddr *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
u32 minor_version, rpc_authflavor_t au_flavor)
{ {
struct nfs_client_initdata cl_init = { struct nfs_client_initdata cl_init = {
.addr = ds_addr, .addr = ds_addr,
.addrlen = ds_addrlen, .addrlen = ds_addrlen,
.nfs_mod = &nfs_v4, .nfs_mod = &nfs_v4,
.proto = ds_proto, .proto = ds_proto,
.minorversion = mds_clp->cl_minorversion, .minorversion = minor_version,
.net = mds_clp->cl_net, .net = mds_clp->cl_net,
}; };
struct rpc_timeout ds_timeout; struct rpc_timeout ds_timeout;
...@@ -874,7 +875,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, ...@@ -874,7 +875,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
*/ */
nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
mds_clp->cl_rpcclient->cl_auth->au_flavor); au_flavor);
dprintk("<-- %s %p\n", __func__, clp); dprintk("<-- %s %p\n", __func__, clp);
return clp; return clp;
......
This diff is collapsed.
...@@ -1003,11 +1003,11 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m ...@@ -1003,11 +1003,11 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m
struct nfs_seqid *new; struct nfs_seqid *new;
new = kmalloc(sizeof(*new), gfp_mask); new = kmalloc(sizeof(*new), gfp_mask);
if (new != NULL) { if (new == NULL)
new->sequence = counter; return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&new->list); new->sequence = counter;
new->task = NULL; INIT_LIST_HEAD(&new->list);
} new->task = NULL;
return new; return new;
} }
...@@ -1015,7 +1015,7 @@ void nfs_release_seqid(struct nfs_seqid *seqid) ...@@ -1015,7 +1015,7 @@ void nfs_release_seqid(struct nfs_seqid *seqid)
{ {
struct nfs_seqid_counter *sequence; struct nfs_seqid_counter *sequence;
if (list_empty(&seqid->list)) if (seqid == NULL || list_empty(&seqid->list))
return; return;
sequence = seqid->sequence; sequence = seqid->sequence;
spin_lock(&sequence->lock); spin_lock(&sequence->lock);
...@@ -1071,13 +1071,15 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) ...@@ -1071,13 +1071,15 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
{ {
struct nfs4_state_owner *sp = container_of(seqid->sequence, struct nfs4_state_owner *sp;
struct nfs4_state_owner, so_seqid);
struct nfs_server *server = sp->so_server; if (seqid == NULL)
return;
sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
if (status == -NFS4ERR_BAD_SEQID) if (status == -NFS4ERR_BAD_SEQID)
nfs4_drop_state_owner(sp); nfs4_drop_state_owner(sp);
if (!nfs4_has_session(server->nfs_client)) if (!nfs4_has_session(sp->so_server->nfs_client))
nfs_increment_seqid(status, seqid); nfs_increment_seqid(status, seqid);
} }
...@@ -1088,14 +1090,18 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) ...@@ -1088,14 +1090,18 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
*/ */
void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
{ {
nfs_increment_seqid(status, seqid); if (seqid != NULL)
nfs_increment_seqid(status, seqid);
} }
int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
{ {
struct nfs_seqid_counter *sequence = seqid->sequence; struct nfs_seqid_counter *sequence;
int status = 0; int status = 0;
if (seqid == NULL)
goto out;
sequence = seqid->sequence;
spin_lock(&sequence->lock); spin_lock(&sequence->lock);
seqid->task = task; seqid->task = task;
if (list_empty(&seqid->list)) if (list_empty(&seqid->list))
...@@ -1106,6 +1112,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) ...@@ -1106,6 +1112,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
status = -EAGAIN; status = -EAGAIN;
unlock: unlock:
spin_unlock(&sequence->lock); spin_unlock(&sequence->lock);
out:
return status; return status;
} }
......
...@@ -346,6 +346,9 @@ static int __init init_nfs_v4(void) ...@@ -346,6 +346,9 @@ static int __init init_nfs_v4(void)
static void __exit exit_nfs_v4(void) static void __exit exit_nfs_v4(void)
{ {
/* Not called in the _init(), conditionally loaded */
nfs4_pnfs_v3_ds_connect_unload();
unregister_nfs_version(&nfs_v4); unregister_nfs_version(&nfs_v4);
nfs4_unregister_sysctl(); nfs4_unregister_sysctl();
nfs_idmap_quit(); nfs_idmap_quit();
......
This diff is collapsed.
...@@ -261,11 +261,11 @@ static int __init root_nfs_data(char *cmdline) ...@@ -261,11 +261,11 @@ static int __init root_nfs_data(char *cmdline)
*/ */
len = snprintf(nfs_export_path, sizeof(nfs_export_path), len = snprintf(nfs_export_path, sizeof(nfs_export_path),
tmp, utsname()->nodename); tmp, utsname()->nodename);
if (len > (int)sizeof(nfs_export_path)) if (len >= (int)sizeof(nfs_export_path))
goto out_devnametoolong; goto out_devnametoolong;
len = snprintf(nfs_root_device, sizeof(nfs_root_device), len = snprintf(nfs_root_device, sizeof(nfs_root_device),
"%pI4:%s", &servaddr, nfs_export_path); "%pI4:%s", &servaddr, nfs_export_path);
if (len > (int)sizeof(nfs_root_device)) if (len >= (int)sizeof(nfs_root_device))
goto out_devnametoolong; goto out_devnametoolong;
retval = 0; retval = 0;
......
...@@ -537,11 +537,12 @@ int objio_write_pagelist(struct nfs_pgio_header *hdr, int how) ...@@ -537,11 +537,12 @@ int objio_write_pagelist(struct nfs_pgio_header *hdr, int how)
static size_t objio_pg_test(struct nfs_pageio_descriptor *pgio, 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)
{ {
struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(pgio);
unsigned int size; unsigned int size;
size = pnfs_generic_pg_test(pgio, prev, req); size = pnfs_generic_pg_test(pgio, prev, req);
if (!size || pgio->pg_count + req->wb_bytes > if (!size || mirror->pg_count + req->wb_bytes >
(unsigned long)pgio->pg_layout_private) (unsigned long)pgio->pg_layout_private)
return 0; return 0;
...@@ -607,12 +608,14 @@ static const struct nfs_pageio_ops objio_pg_read_ops = { ...@@ -607,12 +608,14 @@ static const struct nfs_pageio_ops objio_pg_read_ops = {
.pg_init = objio_init_read, .pg_init = objio_init_read,
.pg_test = objio_pg_test, .pg_test = objio_pg_test,
.pg_doio = pnfs_generic_pg_readpages, .pg_doio = pnfs_generic_pg_readpages,
.pg_cleanup = pnfs_generic_pg_cleanup,
}; };
static const struct nfs_pageio_ops objio_pg_write_ops = { static const struct nfs_pageio_ops objio_pg_write_ops = {
.pg_init = objio_init_write, .pg_init = objio_init_write,
.pg_test = objio_pg_test, .pg_test = objio_pg_test,
.pg_doio = pnfs_generic_pg_writepages, .pg_doio = pnfs_generic_pg_writepages,
.pg_cleanup = pnfs_generic_pg_cleanup,
}; };
static struct pnfs_layoutdriver_type objlayout_type = { static struct pnfs_layoutdriver_type objlayout_type = {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -70,8 +70,15 @@ EXPORT_SYMBOL_GPL(nfs_pageio_init_read); ...@@ -70,8 +70,15 @@ 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)
{ {
struct nfs_pgio_mirror *mirror;
pgio->pg_ops = &nfs_pgio_rw_ops; pgio->pg_ops = &nfs_pgio_rw_ops;
pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
/* read path should never have more than one mirror */
WARN_ON_ONCE(pgio->pg_mirror_count != 1);
mirror = &pgio->pg_mirrors[0];
mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
} }
EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
...@@ -81,6 +88,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, ...@@ -81,6 +88,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
struct nfs_page *new; struct nfs_page *new;
unsigned int len; unsigned int len;
struct nfs_pageio_descriptor pgio; struct nfs_pageio_descriptor pgio;
struct nfs_pgio_mirror *pgm;
len = nfs_page_length(page); len = nfs_page_length(page);
if (len == 0) if (len == 0)
...@@ -97,7 +105,13 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, ...@@ -97,7 +105,13 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
&nfs_async_read_completion_ops); &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;
/* It doesn't make sense to do mirrored reads! */
WARN_ON_ONCE(pgio.pg_mirror_count != 1);
pgm = &pgio.pg_mirrors[0];
NFS_I(inode)->read_io += pgm->pg_bytes_written;
return 0; return 0;
} }
...@@ -168,13 +182,14 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr) ...@@ -168,13 +182,14 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
static void nfs_initiate_read(struct nfs_pgio_header *hdr, static void nfs_initiate_read(struct nfs_pgio_header *hdr,
struct rpc_message *msg, struct rpc_message *msg,
const struct nfs_rpc_ops *rpc_ops,
struct rpc_task_setup *task_setup_data, int how) struct rpc_task_setup *task_setup_data, int how)
{ {
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
task_setup_data->flags |= swap_flags; task_setup_data->flags |= swap_flags;
NFS_PROTO(inode)->read_setup(hdr, msg); rpc_ops->read_setup(hdr, msg);
} }
static void static void
...@@ -351,6 +366,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -351,6 +366,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages) struct list_head *pages, unsigned nr_pages)
{ {
struct nfs_pageio_descriptor pgio; struct nfs_pageio_descriptor pgio;
struct nfs_pgio_mirror *pgm;
struct nfs_readdesc desc = { struct nfs_readdesc desc = {
.pgio = &pgio, .pgio = &pgio,
}; };
...@@ -386,10 +402,15 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -386,10 +402,15 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
&nfs_async_read_completion_ops); &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);
nfs_pageio_complete(&pgio); nfs_pageio_complete(&pgio);
NFS_I(inode)->read_io += pgio.pg_bytes_written;
npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* It doesn't make sense to do mirrored reads! */
WARN_ON_ONCE(pgio.pg_mirror_count != 1);
pgm = &pgio.pg_mirrors[0];
NFS_I(inode)->read_io += pgm->pg_bytes_written;
npages = (pgm->pg_bytes_written + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
nfs_add_stats(inode, NFSIOS_READPAGES, npages); nfs_add_stats(inode, NFSIOS_READPAGES, npages);
read_complete: read_complete:
put_nfs_open_context(desc.ctx); put_nfs_open_context(desc.ctx);
......
...@@ -405,12 +405,15 @@ void __exit unregister_nfs_fs(void) ...@@ -405,12 +405,15 @@ void __exit unregister_nfs_fs(void)
unregister_filesystem(&nfs_fs_type); unregister_filesystem(&nfs_fs_type);
} }
void nfs_sb_active(struct super_block *sb) bool nfs_sb_active(struct super_block *sb)
{ {
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
if (atomic_inc_return(&server->active) == 1) if (!atomic_inc_not_zero(&sb->s_active))
atomic_inc(&sb->s_active); return false;
if (atomic_inc_return(&server->active) != 1)
atomic_dec(&sb->s_active);
return true;
} }
EXPORT_SYMBOL_GPL(nfs_sb_active); EXPORT_SYMBOL_GPL(nfs_sb_active);
......
This diff is collapsed.
...@@ -516,6 +516,7 @@ enum pnfs_layouttype { ...@@ -516,6 +516,7 @@ enum pnfs_layouttype {
LAYOUT_NFSV4_1_FILES = 1, LAYOUT_NFSV4_1_FILES = 1,
LAYOUT_OSD2_OBJECTS = 2, LAYOUT_OSD2_OBJECTS = 2,
LAYOUT_BLOCK_VOLUME = 3, LAYOUT_BLOCK_VOLUME = 3,
LAYOUT_FLEX_FILES = 4,
}; };
/* used for both layout return and recall */ /* used for both layout return and recall */
......
...@@ -77,10 +77,6 @@ struct nfs_client { ...@@ -77,10 +77,6 @@ struct nfs_client {
/* Client owner identifier */ /* Client owner identifier */
const char * cl_owner_id; const char * cl_owner_id;
/* Our own IP address, as a null-terminated string.
* This is used to generate the mv0 callback address.
*/
char cl_ipaddr[48];
u32 cl_cb_ident; /* v4.0 callback identifier */ u32 cl_cb_ident; /* v4.0 callback identifier */
const struct nfs4_minor_version_ops *cl_mvops; const struct nfs4_minor_version_ops *cl_mvops;
unsigned long cl_mig_gen; unsigned long cl_mig_gen;
...@@ -108,6 +104,11 @@ struct nfs_client { ...@@ -108,6 +104,11 @@ struct nfs_client {
#define NFS_SP4_MACH_CRED_COMMIT 6 /* COMMIT */ #define NFS_SP4_MACH_CRED_COMMIT 6 /* COMMIT */
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
/* Our own IP address, as a null-terminated string.
* This is used to generate the mv0 callback address.
*/
char cl_ipaddr[48];
#ifdef CONFIG_NFS_FSCACHE #ifdef CONFIG_NFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */ struct fscache_cookie *fscache; /* client index cache cookie */
#endif #endif
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment