Commit 86e00412 authored by Mike Snitzer's avatar Mike Snitzer Committed by Anna Schumaker
Browse files

nfs: cache all open LOCALIO nfsd_file(s) in client



This commit switches from leaning heavily on NFSD's filecache (in
terms of GC'd nfsd_files) back to caching nfsd_files in the
client. A later commit will add the callback mechanism needed to
allow NFSD to force the NFS client to cleanup all cached nfsd_files.

Add nfs_fh_localio_init() and 'struct nfs_fh_localio' to cache opened
nfsd_file(s) (both a RO and RW nfsd_file is able to be opened and
cached for a given nfs_fh).

Update nfs_local_open_fh() to cache the nfsd_file once it is opened
using __nfs_local_open_fh().

Introduce nfs_close_local_fh() to clear the cached open nfsd_files and
call nfs_to_nfsd_file_put_local().

Refcounting is such that:
- nfs_local_open_fh() is paired with nfs_close_local_fh().
- __nfs_local_open_fh() is paired with nfs_to_nfsd_file_put_local().
- nfs_local_file_get() is paired with nfs_local_file_put().

Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarAnna Schumaker <anna.schumaker@oracle.com>
parent 4ee7ba40
Loading
Loading
Loading
Loading
+13 −12
Original line number Diff line number Diff line
@@ -164,18 +164,17 @@ decode_name(struct xdr_stream *xdr, u32 *id)
}

static struct nfsd_file *
ff_local_open_fh(struct nfs_client *clp, const struct cred *cred,
ff_local_open_fh(struct pnfs_layout_segment *lseg, u32 ds_idx,
		 struct nfs_client *clp, const struct cred *cred,
		 struct nfs_fh *fh, fmode_t mode)
{
	if (mode & FMODE_WRITE) {
		/*
		 * Always request read and write access since this corresponds
		 * to a rw layout.
		 */
		mode |= FMODE_READ;
	}
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
	struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, ds_idx);

	return nfs_local_open_fh(clp, cred, fh, mode);
	return nfs_local_open_fh(clp, cred, fh, &mirror->nfl, mode);
#else
	return NULL;
#endif
}

static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
@@ -247,6 +246,7 @@ static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
		spin_lock_init(&mirror->lock);
		refcount_set(&mirror->ref, 1);
		INIT_LIST_HEAD(&mirror->mirrors);
		nfs_localio_file_init(&mirror->nfl);
	}
	return mirror;
}
@@ -257,6 +257,7 @@ static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)

	ff_layout_remove_mirror(mirror);
	kfree(mirror->fh_versions);
	nfs_close_local_fh(&mirror->nfl);
	cred = rcu_access_pointer(mirror->ro_cred);
	put_cred(cred);
	cred = rcu_access_pointer(mirror->rw_cred);
@@ -1820,7 +1821,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
	hdr->mds_offset = offset;

	/* Start IO accounting for local read */
	localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh, FMODE_READ);
	localio = ff_local_open_fh(lseg, idx, ds->ds_clp, ds_cred, fh, FMODE_READ);
	if (localio) {
		hdr->task.tk_start = ktime_get();
		ff_layout_read_record_layoutstats_start(&hdr->task, hdr);
@@ -1896,7 +1897,7 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
	hdr->args.offset = offset;

	/* Start IO accounting for local write */
	localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh,
	localio = ff_local_open_fh(lseg, idx, ds->ds_clp, ds_cred, fh,
				   FMODE_READ|FMODE_WRITE);
	if (localio) {
		hdr->task.tk_start = ktime_get();
@@ -1981,7 +1982,7 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
		data->args.fh = fh;

	/* Start IO accounting for local commit */
	localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh,
	localio = ff_local_open_fh(lseg, idx, ds->ds_clp, ds_cred, fh,
				   FMODE_READ|FMODE_WRITE);
	if (localio) {
		data->task.tk_start = ktime_get();
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct nfs4_ff_layout_mirror {
	nfs4_stateid			stateid;
	const struct cred __rcu		*ro_cred;
	const struct cred __rcu		*rw_cred;
	struct nfs_file_localio		nfl;
	refcount_t			ref;
	spinlock_t			lock;
	unsigned long			flags;
+3 −0
Original line number Diff line number Diff line
@@ -1137,6 +1137,8 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
	ctx->lock_context.open_context = ctx;
	INIT_LIST_HEAD(&ctx->list);
	ctx->mdsthreshold = NULL;
	nfs_localio_file_init(&ctx->nfl);

	return ctx;
}
EXPORT_SYMBOL_GPL(alloc_nfs_open_context);
@@ -1168,6 +1170,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
	nfs_sb_deactive(sb);
	put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1));
	kfree(ctx->mdsthreshold);
	nfs_close_local_fh(&ctx->nfl);
	kfree_rcu(ctx, rcu_head);
}

+3 −1
Original line number Diff line number Diff line
@@ -460,6 +460,7 @@ extern void nfs_local_probe(struct nfs_client *);
extern struct nfsd_file *nfs_local_open_fh(struct nfs_client *,
					   const struct cred *,
					   struct nfs_fh *,
					   struct nfs_file_localio *,
					   const fmode_t);
extern int nfs_local_doio(struct nfs_client *,
			  struct nfsd_file *,
@@ -475,7 +476,8 @@ static inline void nfs_local_disable(struct nfs_client *clp) {}
static inline void nfs_local_probe(struct nfs_client *clp) {}
static inline struct nfsd_file *
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
		  struct nfs_fh *fh, const fmode_t mode)
		  struct nfs_fh *fh, struct nfs_file_localio *nfl,
		  const fmode_t mode)
{
	return NULL;
}
+72 −17
Original line number Diff line number Diff line
@@ -211,27 +211,33 @@ void nfs_local_probe(struct nfs_client *clp)
}
EXPORT_SYMBOL_GPL(nfs_local_probe);

static inline struct nfsd_file *nfs_local_file_get(struct nfsd_file *nf)
{
	return nfs_to->nfsd_file_get(nf);
}

static inline void nfs_local_file_put(struct nfsd_file *nf)
{
	nfs_to->nfsd_file_put(nf);
}

/*
 * nfs_local_open_fh - open a local filehandle in terms of nfsd_file
 * __nfs_local_open_fh - open a local filehandle in terms of nfsd_file.
 *
 * Returns a pointer to a struct nfsd_file or NULL
 * Returns a pointer to a struct nfsd_file or ERR_PTR.
 * Caller must release returned nfsd_file with nfs_to_nfsd_file_put_local().
 */
struct nfsd_file *
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
		  struct nfs_fh *fh, const fmode_t mode)
static struct nfsd_file *
__nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
		    struct nfs_fh *fh, struct nfs_file_localio *nfl,
		    const fmode_t mode)
{
	struct nfsd_file *localio;
	int status;

	if (!nfs_server_is_local(clp))
		return NULL;
	if (mode & ~(FMODE_READ | FMODE_WRITE))
		return NULL;

	localio = nfs_open_local_fh(&clp->cl_uuid, clp->cl_rpcclient,
				    cred, fh, mode);
				    cred, fh, nfl, mode);
	if (IS_ERR(localio)) {
		status = PTR_ERR(localio);
		int status = PTR_ERR(localio);
		trace_nfs_local_open_fh(fh, mode, status);
		switch (status) {
		case -ENOMEM:
@@ -240,10 +246,59 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
			/* Revalidate localio, will disable if unsupported */
			nfs_local_probe(clp);
		}
		return NULL;
	}
	return localio;
}

/*
 * nfs_local_open_fh - open a local filehandle in terms of nfsd_file.
 * First checking if the open nfsd_file is already cached, otherwise
 * must __nfs_local_open_fh and insert the nfsd_file in nfs_file_localio.
 *
 * Returns a pointer to a struct nfsd_file or NULL.
 */
struct nfsd_file *
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
		  struct nfs_fh *fh, struct nfs_file_localio *nfl,
		  const fmode_t mode)
{
	struct nfsd_file *nf, *new, __rcu **pnf;

	if (!nfs_server_is_local(clp))
		return NULL;
	if (mode & ~(FMODE_READ | FMODE_WRITE))
		return NULL;

	if (mode & FMODE_WRITE)
		pnf = &nfl->rw_file;
	else
		pnf = &nfl->ro_file;

	new = NULL;
	rcu_read_lock();
	nf = rcu_dereference(*pnf);
	if (!nf) {
		rcu_read_unlock();
		new = __nfs_local_open_fh(clp, cred, fh, nfl, mode);
		if (IS_ERR(new))
			return NULL;
		/* try to swap in the pointer */
		spin_lock(&clp->cl_uuid.lock);
		nf = rcu_dereference_protected(*pnf, 1);
		if (!nf) {
			nf = new;
			new = NULL;
			rcu_assign_pointer(*pnf, nf);
		}
		spin_unlock(&clp->cl_uuid.lock);
		rcu_read_lock();
	}
	nf = nfs_local_file_get(nf);
	rcu_read_unlock();
	if (new)
		nfs_to_nfsd_file_put_local(new);
	return nf;
}
EXPORT_SYMBOL_GPL(nfs_local_open_fh);

static struct bio_vec *
@@ -347,7 +402,7 @@ nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
{
	struct nfs_pgio_header *hdr = iocb->hdr;

	nfs_to_nfsd_file_put_local(iocb->localio);
	nfs_local_file_put(iocb->localio);
	nfs_local_iocb_free(iocb);
	nfs_local_hdr_release(hdr, hdr->task.tk_ops);
}
@@ -694,7 +749,7 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
	if (status != 0) {
		if (status == -EAGAIN)
			nfs_local_disable(clp);
		nfs_to_nfsd_file_put_local(localio);
		nfs_local_file_put(localio);
		hdr->task.tk_status = status;
		nfs_local_hdr_release(hdr, call_ops);
	}
@@ -745,7 +800,7 @@ nfs_local_release_commit_data(struct nfsd_file *localio,
		struct nfs_commit_data *data,
		const struct rpc_call_ops *call_ops)
{
	nfs_to_nfsd_file_put_local(localio);
	nfs_local_file_put(localio);
	call_ops->rpc_call_done(&data->task, data);
	call_ops->rpc_release(data);
}
Loading