Skip to content

Commit 86e0041

Browse files
Mike SnitzerAnna Schumaker
authored andcommitted
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: Mike Snitzer <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 4ee7ba4 commit 86e0041

File tree

10 files changed

+176
-44
lines changed

10 files changed

+176
-44
lines changed

fs/nfs/flexfilelayout/flexfilelayout.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,17 @@ decode_name(struct xdr_stream *xdr, u32 *id)
164164
}
165165

166166
static struct nfsd_file *
167-
ff_local_open_fh(struct nfs_client *clp, const struct cred *cred,
167+
ff_local_open_fh(struct pnfs_layout_segment *lseg, u32 ds_idx,
168+
struct nfs_client *clp, const struct cred *cred,
168169
struct nfs_fh *fh, fmode_t mode)
169170
{
170-
if (mode & FMODE_WRITE) {
171-
/*
172-
* Always request read and write access since this corresponds
173-
* to a rw layout.
174-
*/
175-
mode |= FMODE_READ;
176-
}
171+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
172+
struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, ds_idx);
177173

178-
return nfs_local_open_fh(clp, cred, fh, mode);
174+
return nfs_local_open_fh(clp, cred, fh, &mirror->nfl, mode);
175+
#else
176+
return NULL;
177+
#endif
179178
}
180179

181180
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)
247246
spin_lock_init(&mirror->lock);
248247
refcount_set(&mirror->ref, 1);
249248
INIT_LIST_HEAD(&mirror->mirrors);
249+
nfs_localio_file_init(&mirror->nfl);
250250
}
251251
return mirror;
252252
}
@@ -257,6 +257,7 @@ static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)
257257

258258
ff_layout_remove_mirror(mirror);
259259
kfree(mirror->fh_versions);
260+
nfs_close_local_fh(&mirror->nfl);
260261
cred = rcu_access_pointer(mirror->ro_cred);
261262
put_cred(cred);
262263
cred = rcu_access_pointer(mirror->rw_cred);
@@ -1820,7 +1821,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
18201821
hdr->mds_offset = offset;
18211822

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

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

19831984
/* Start IO accounting for local commit */
1984-
localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh,
1985+
localio = ff_local_open_fh(lseg, idx, ds->ds_clp, ds_cred, fh,
19851986
FMODE_READ|FMODE_WRITE);
19861987
if (localio) {
19871988
data->task.tk_start = ktime_get();

fs/nfs/flexfilelayout/flexfilelayout.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct nfs4_ff_layout_mirror {
8383
nfs4_stateid stateid;
8484
const struct cred __rcu *ro_cred;
8585
const struct cred __rcu *rw_cred;
86+
struct nfs_file_localio nfl;
8687
refcount_t ref;
8788
spinlock_t lock;
8889
unsigned long flags;

fs/nfs/inode.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,8 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
11371137
ctx->lock_context.open_context = ctx;
11381138
INIT_LIST_HEAD(&ctx->list);
11391139
ctx->mdsthreshold = NULL;
1140+
nfs_localio_file_init(&ctx->nfl);
1141+
11401142
return ctx;
11411143
}
11421144
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)
11681170
nfs_sb_deactive(sb);
11691171
put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1));
11701172
kfree(ctx->mdsthreshold);
1173+
nfs_close_local_fh(&ctx->nfl);
11711174
kfree_rcu(ctx, rcu_head);
11721175
}
11731176

fs/nfs/internal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ extern void nfs_local_probe(struct nfs_client *);
460460
extern struct nfsd_file *nfs_local_open_fh(struct nfs_client *,
461461
const struct cred *,
462462
struct nfs_fh *,
463+
struct nfs_file_localio *,
463464
const fmode_t);
464465
extern int nfs_local_doio(struct nfs_client *,
465466
struct nfsd_file *,
@@ -475,7 +476,8 @@ static inline void nfs_local_disable(struct nfs_client *clp) {}
475476
static inline void nfs_local_probe(struct nfs_client *clp) {}
476477
static inline struct nfsd_file *
477478
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
478-
struct nfs_fh *fh, const fmode_t mode)
479+
struct nfs_fh *fh, struct nfs_file_localio *nfl,
480+
const fmode_t mode)
479481
{
480482
return NULL;
481483
}

fs/nfs/localio.c

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -211,27 +211,33 @@ void nfs_local_probe(struct nfs_client *clp)
211211
}
212212
EXPORT_SYMBOL_GPL(nfs_local_probe);
213213

214+
static inline struct nfsd_file *nfs_local_file_get(struct nfsd_file *nf)
215+
{
216+
return nfs_to->nfsd_file_get(nf);
217+
}
218+
219+
static inline void nfs_local_file_put(struct nfsd_file *nf)
220+
{
221+
nfs_to->nfsd_file_put(nf);
222+
}
223+
214224
/*
215-
* nfs_local_open_fh - open a local filehandle in terms of nfsd_file
225+
* __nfs_local_open_fh - open a local filehandle in terms of nfsd_file.
216226
*
217-
* Returns a pointer to a struct nfsd_file or NULL
227+
* Returns a pointer to a struct nfsd_file or ERR_PTR.
228+
* Caller must release returned nfsd_file with nfs_to_nfsd_file_put_local().
218229
*/
219-
struct nfsd_file *
220-
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
221-
struct nfs_fh *fh, const fmode_t mode)
230+
static struct nfsd_file *
231+
__nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
232+
struct nfs_fh *fh, struct nfs_file_localio *nfl,
233+
const fmode_t mode)
222234
{
223235
struct nfsd_file *localio;
224-
int status;
225-
226-
if (!nfs_server_is_local(clp))
227-
return NULL;
228-
if (mode & ~(FMODE_READ | FMODE_WRITE))
229-
return NULL;
230236

231237
localio = nfs_open_local_fh(&clp->cl_uuid, clp->cl_rpcclient,
232-
cred, fh, mode);
238+
cred, fh, nfl, mode);
233239
if (IS_ERR(localio)) {
234-
status = PTR_ERR(localio);
240+
int status = PTR_ERR(localio);
235241
trace_nfs_local_open_fh(fh, mode, status);
236242
switch (status) {
237243
case -ENOMEM:
@@ -240,10 +246,59 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
240246
/* Revalidate localio, will disable if unsupported */
241247
nfs_local_probe(clp);
242248
}
243-
return NULL;
244249
}
245250
return localio;
246251
}
252+
253+
/*
254+
* nfs_local_open_fh - open a local filehandle in terms of nfsd_file.
255+
* First checking if the open nfsd_file is already cached, otherwise
256+
* must __nfs_local_open_fh and insert the nfsd_file in nfs_file_localio.
257+
*
258+
* Returns a pointer to a struct nfsd_file or NULL.
259+
*/
260+
struct nfsd_file *
261+
nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
262+
struct nfs_fh *fh, struct nfs_file_localio *nfl,
263+
const fmode_t mode)
264+
{
265+
struct nfsd_file *nf, *new, __rcu **pnf;
266+
267+
if (!nfs_server_is_local(clp))
268+
return NULL;
269+
if (mode & ~(FMODE_READ | FMODE_WRITE))
270+
return NULL;
271+
272+
if (mode & FMODE_WRITE)
273+
pnf = &nfl->rw_file;
274+
else
275+
pnf = &nfl->ro_file;
276+
277+
new = NULL;
278+
rcu_read_lock();
279+
nf = rcu_dereference(*pnf);
280+
if (!nf) {
281+
rcu_read_unlock();
282+
new = __nfs_local_open_fh(clp, cred, fh, nfl, mode);
283+
if (IS_ERR(new))
284+
return NULL;
285+
/* try to swap in the pointer */
286+
spin_lock(&clp->cl_uuid.lock);
287+
nf = rcu_dereference_protected(*pnf, 1);
288+
if (!nf) {
289+
nf = new;
290+
new = NULL;
291+
rcu_assign_pointer(*pnf, nf);
292+
}
293+
spin_unlock(&clp->cl_uuid.lock);
294+
rcu_read_lock();
295+
}
296+
nf = nfs_local_file_get(nf);
297+
rcu_read_unlock();
298+
if (new)
299+
nfs_to_nfsd_file_put_local(new);
300+
return nf;
301+
}
247302
EXPORT_SYMBOL_GPL(nfs_local_open_fh);
248303

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

350-
nfs_to_nfsd_file_put_local(iocb->localio);
405+
nfs_local_file_put(iocb->localio);
351406
nfs_local_iocb_free(iocb);
352407
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
353408
}
@@ -694,7 +749,7 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
694749
if (status != 0) {
695750
if (status == -EAGAIN)
696751
nfs_local_disable(clp);
697-
nfs_to_nfsd_file_put_local(localio);
752+
nfs_local_file_put(localio);
698753
hdr->task.tk_status = status;
699754
nfs_local_hdr_release(hdr, call_ops);
700755
}
@@ -745,7 +800,7 @@ nfs_local_release_commit_data(struct nfsd_file *localio,
745800
struct nfs_commit_data *data,
746801
const struct rpc_call_ops *call_ops)
747802
{
748-
nfs_to_nfsd_file_put_local(localio);
803+
nfs_local_file_put(localio);
749804
call_ops->rpc_call_done(&data->task, data);
750805
call_ops->rpc_release(data);
751806
}

fs/nfs/pagelist.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,8 +961,9 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
961961
struct nfs_client *clp = NFS_SERVER(hdr->inode)->nfs_client;
962962

963963
struct nfsd_file *localio =
964-
nfs_local_open_fh(clp, hdr->cred,
965-
hdr->args.fh, hdr->args.context->mode);
964+
nfs_local_open_fh(clp, hdr->cred, hdr->args.fh,
965+
&hdr->args.context->nfl,
966+
hdr->args.context->mode);
966967

967968
if (NFS_SERVER(hdr->inode)->nfs_client->cl_minorversion)
968969
task_flags = RPC_TASK_MOVEABLE;

fs/nfs/write.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1826,7 +1826,8 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
18261826
task_flags = RPC_TASK_MOVEABLE;
18271827

18281828
localio = nfs_local_open_fh(NFS_SERVER(inode)->nfs_client, data->cred,
1829-
data->args.fh, data->context->mode);
1829+
data->args.fh, &data->context->nfl,
1830+
data->context->mode);
18301831
return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode),
18311832
data->mds_ops, how,
18321833
RPC_TASK_CRED_NOREF | task_flags, localio);

fs/nfs_common/nfslocalio.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <linux/nfslocalio.h>
1010
#include <linux/nfs3.h>
1111
#include <linux/nfs4.h>
12-
#include <linux/nfs_fs_sb.h>
12+
#include <linux/nfs_fs.h>
1313
#include <net/netns/generic.h>
1414

1515
MODULE_LICENSE("GPL");
@@ -151,9 +151,18 @@ void nfs_localio_invalidate_clients(struct list_head *cl_uuid_list)
151151
}
152152
EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
153153

154+
static void nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
155+
{
156+
spin_lock(&nfs_uuid_lock);
157+
if (!nfl->nfs_uuid)
158+
rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
159+
spin_unlock(&nfs_uuid_lock);
160+
}
161+
154162
struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
155163
struct rpc_clnt *rpc_clnt, const struct cred *cred,
156-
const struct nfs_fh *nfs_fh, const fmode_t fmode)
164+
const struct nfs_fh *nfs_fh, struct nfs_file_localio *nfl,
165+
const fmode_t fmode)
157166
{
158167
struct net *net;
159168
struct nfsd_file *localio;
@@ -180,11 +189,50 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
180189
cred, nfs_fh, fmode);
181190
if (IS_ERR(localio))
182191
nfs_to_nfsd_net_put(net);
192+
else
193+
nfs_uuid_add_file(uuid, nfl);
183194

184195
return localio;
185196
}
186197
EXPORT_SYMBOL_GPL(nfs_open_local_fh);
187198

199+
void nfs_close_local_fh(struct nfs_file_localio *nfl)
200+
{
201+
struct nfsd_file *ro_nf = NULL;
202+
struct nfsd_file *rw_nf = NULL;
203+
nfs_uuid_t *nfs_uuid;
204+
205+
rcu_read_lock();
206+
nfs_uuid = rcu_dereference(nfl->nfs_uuid);
207+
if (!nfs_uuid) {
208+
/* regular (non-LOCALIO) NFS will hammer this */
209+
rcu_read_unlock();
210+
return;
211+
}
212+
213+
ro_nf = rcu_access_pointer(nfl->ro_file);
214+
rw_nf = rcu_access_pointer(nfl->rw_file);
215+
if (ro_nf || rw_nf) {
216+
spin_lock(&nfs_uuid_lock);
217+
if (ro_nf)
218+
ro_nf = rcu_dereference_protected(xchg(&nfl->ro_file, NULL), 1);
219+
if (rw_nf)
220+
rw_nf = rcu_dereference_protected(xchg(&nfl->rw_file, NULL), 1);
221+
222+
rcu_assign_pointer(nfl->nfs_uuid, NULL);
223+
spin_unlock(&nfs_uuid_lock);
224+
rcu_read_unlock();
225+
226+
if (ro_nf)
227+
nfs_to_nfsd_file_put_local(ro_nf);
228+
if (rw_nf)
229+
nfs_to_nfsd_file_put_local(rw_nf);
230+
return;
231+
}
232+
rcu_read_unlock();
233+
}
234+
EXPORT_SYMBOL_GPL(nfs_close_local_fh);
235+
188236
/*
189237
* The NFS LOCALIO code needs to call into NFSD using various symbols,
190238
* but cannot be statically linked, because that will make the NFS

include/linux/nfs_fs.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,23 @@ struct nfs_lock_context {
7777
struct rcu_head rcu_head;
7878
};
7979

80+
struct nfs_file_localio {
81+
struct nfsd_file __rcu *ro_file;
82+
struct nfsd_file __rcu *rw_file;
83+
struct list_head list;
84+
void __rcu *nfs_uuid; /* opaque pointer to 'nfs_uuid_t' */
85+
};
86+
87+
static inline void nfs_localio_file_init(struct nfs_file_localio *nfl)
88+
{
89+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
90+
nfl->ro_file = NULL;
91+
nfl->rw_file = NULL;
92+
INIT_LIST_HEAD(&nfl->list);
93+
nfl->nfs_uuid = NULL;
94+
#endif
95+
}
96+
8097
struct nfs4_state;
8198
struct nfs_open_context {
8299
struct nfs_lock_context lock_context;
@@ -87,15 +104,16 @@ struct nfs_open_context {
87104
struct nfs4_state *state;
88105
fmode_t mode;
89106

107+
int error;
90108
unsigned long flags;
91109
#define NFS_CONTEXT_BAD (2)
92110
#define NFS_CONTEXT_UNLOCK (3)
93111
#define NFS_CONTEXT_FILE_OPEN (4)
94-
int error;
95112

96-
struct list_head list;
97113
struct nfs4_threshold *mdsthreshold;
114+
struct list_head list;
98115
struct rcu_head rcu_head;
116+
struct nfs_file_localio nfl;
99117
};
100118

101119
struct nfs_open_dir_context {

0 commit comments

Comments
 (0)