Skip to content

Commit 0b3a551

Browse files
jtlaytonchucklever
authored andcommitted
nfsd: fix handling of cached open files in nfsd4_open codepath
Commit fb70bf1 ("NFSD: Instantiate a struct file when creating a regular NFSv4 file") added the ability to cache an open fd over a compound. There are a couple of problems with the way this currently works: It's racy, as a newly-created nfsd_file can end up with its PENDING bit cleared while the nf is hashed, and the nf_file pointer is still zeroed out. Other tasks can find it in this state and they expect to see a valid nf_file, and can oops if nf_file is NULL. Also, there is no guarantee that we'll end up creating a new nfsd_file if one is already in the hash. If an extant entry is in the hash with a valid nf_file, nfs4_get_vfs_file will clobber its nf_file pointer with the value of op_file and the old nf_file will leak. Fix both issues by making a new nfsd_file_acquirei_opened variant that takes an optional file pointer. If one is present when this is called, we'll take a new reference to it instead of trying to open the file. If the nfsd_file already has a valid nf_file, we'll just ignore the optional file and pass the nfsd_file back as-is. Also rework the tracepoints a bit to allow for an "opened" variant and don't try to avoid counting acquisitions in the case where we already have a cached open file. Fixes: fb70bf1 ("NFSD: Instantiate a struct file when creating a regular NFSv4 file") Cc: Trond Myklebust <trondmy@hammerspace.com> Reported-by: Stanislav Saner <ssaner@redhat.com> Reported-and-Tested-by: Ruben Vestergaard <rubenv@drcmr.dk> Reported-and-Tested-by: Torkil Svensgaard <torkil@drcmr.dk> Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent cad8533 commit 0b3a551

File tree

4 files changed

+42
-71
lines changed

4 files changed

+42
-71
lines changed

fs/nfsd/filecache.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,8 +1071,8 @@ nfsd_file_is_cached(struct inode *inode)
10711071

10721072
static __be32
10731073
nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
1074-
unsigned int may_flags, struct nfsd_file **pnf,
1075-
bool open, bool want_gc)
1074+
unsigned int may_flags, struct file *file,
1075+
struct nfsd_file **pnf, bool want_gc)
10761076
{
10771077
struct nfsd_file_lookup_key key = {
10781078
.type = NFSD_FILE_KEY_FULL,
@@ -1147,8 +1147,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
11471147
status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
11481148
out:
11491149
if (status == nfs_ok) {
1150-
if (open)
1151-
this_cpu_inc(nfsd_file_acquisitions);
1150+
this_cpu_inc(nfsd_file_acquisitions);
11521151
*pnf = nf;
11531152
} else {
11541153
if (refcount_dec_and_test(&nf->nf_ref))
@@ -1158,20 +1157,23 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
11581157

11591158
out_status:
11601159
put_cred(key.cred);
1161-
if (open)
1162-
trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
1160+
trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
11631161
return status;
11641162

11651163
open_file:
11661164
trace_nfsd_file_alloc(nf);
11671165
nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);
11681166
if (nf->nf_mark) {
1169-
if (open) {
1167+
if (file) {
1168+
get_file(file);
1169+
nf->nf_file = file;
1170+
status = nfs_ok;
1171+
trace_nfsd_file_opened(nf, status);
1172+
} else {
11701173
status = nfsd_open_verified(rqstp, fhp, may_flags,
11711174
&nf->nf_file);
11721175
trace_nfsd_file_open(nf, status);
1173-
} else
1174-
status = nfs_ok;
1176+
}
11751177
} else
11761178
status = nfserr_jukebox;
11771179
/*
@@ -1207,7 +1209,7 @@ __be32
12071209
nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
12081210
unsigned int may_flags, struct nfsd_file **pnf)
12091211
{
1210-
return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, true);
1212+
return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
12111213
}
12121214

12131215
/**
@@ -1228,28 +1230,30 @@ __be32
12281230
nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
12291231
unsigned int may_flags, struct nfsd_file **pnf)
12301232
{
1231-
return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, false);
1233+
return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
12321234
}
12331235

12341236
/**
1235-
* nfsd_file_create - Get a struct nfsd_file, do not open
1237+
* nfsd_file_acquire_opened - Get a struct nfsd_file using existing open file
12361238
* @rqstp: the RPC transaction being executed
12371239
* @fhp: the NFS filehandle of the file just created
12381240
* @may_flags: NFSD_MAY_ settings for the file
1241+
* @file: cached, already-open file (may be NULL)
12391242
* @pnf: OUT: new or found "struct nfsd_file" object
12401243
*
1241-
* The nfsd_file_object returned by this API is reference-counted
1242-
* but not garbage-collected. The object is released immediately
1243-
* one RCU grace period after the final nfsd_file_put().
1244+
* Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist,
1245+
* and @file is non-NULL, use it to instantiate a new nfsd_file instead of
1246+
* opening a new one.
12441247
*
12451248
* Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
12461249
* network byte order is returned.
12471250
*/
12481251
__be32
1249-
nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1250-
unsigned int may_flags, struct nfsd_file **pnf)
1252+
nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
1253+
unsigned int may_flags, struct file *file,
1254+
struct nfsd_file **pnf)
12511255
{
1252-
return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, false);
1256+
return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
12531257
}
12541258

12551259
/*

fs/nfsd/filecache.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ __be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
6060
unsigned int may_flags, struct nfsd_file **nfp);
6161
__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
6262
unsigned int may_flags, struct nfsd_file **nfp);
63-
__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
64-
unsigned int may_flags, struct nfsd_file **nfp);
63+
__be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
64+
unsigned int may_flags, struct file *file,
65+
struct nfsd_file **nfp);
6566
int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
6667
#endif /* _FS_NFSD_FILECACHE_H */

fs/nfsd/nfs4state.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5262,18 +5262,10 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
52625262
if (!fp->fi_fds[oflag]) {
52635263
spin_unlock(&fp->fi_lock);
52645264

5265-
if (!open->op_filp) {
5266-
status = nfsd_file_acquire(rqstp, cur_fh, access, &nf);
5267-
if (status != nfs_ok)
5268-
goto out_put_access;
5269-
} else {
5270-
status = nfsd_file_create(rqstp, cur_fh, access, &nf);
5271-
if (status != nfs_ok)
5272-
goto out_put_access;
5273-
nf->nf_file = open->op_filp;
5274-
open->op_filp = NULL;
5275-
trace_nfsd_file_create(rqstp, access, nf);
5276-
}
5265+
status = nfsd_file_acquire_opened(rqstp, cur_fh, access,
5266+
open->op_filp, &nf);
5267+
if (status != nfs_ok)
5268+
goto out_put_access;
52775269

52785270
spin_lock(&fp->fi_lock);
52795271
if (!fp->fi_fds[oflag]) {

fs/nfsd/trace.h

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -981,43 +981,6 @@ TRACE_EVENT(nfsd_file_acquire,
981981
)
982982
);
983983

984-
TRACE_EVENT(nfsd_file_create,
985-
TP_PROTO(
986-
const struct svc_rqst *rqstp,
987-
unsigned int may_flags,
988-
const struct nfsd_file *nf
989-
),
990-
991-
TP_ARGS(rqstp, may_flags, nf),
992-
993-
TP_STRUCT__entry(
994-
__field(const void *, nf_inode)
995-
__field(const void *, nf_file)
996-
__field(unsigned long, may_flags)
997-
__field(unsigned long, nf_flags)
998-
__field(unsigned long, nf_may)
999-
__field(unsigned int, nf_ref)
1000-
__field(u32, xid)
1001-
),
1002-
1003-
TP_fast_assign(
1004-
__entry->nf_inode = nf->nf_inode;
1005-
__entry->nf_file = nf->nf_file;
1006-
__entry->may_flags = may_flags;
1007-
__entry->nf_flags = nf->nf_flags;
1008-
__entry->nf_may = nf->nf_may;
1009-
__entry->nf_ref = refcount_read(&nf->nf_ref);
1010-
__entry->xid = be32_to_cpu(rqstp->rq_xid);
1011-
),
1012-
1013-
TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
1014-
__entry->xid, __entry->nf_inode,
1015-
show_nfsd_may_flags(__entry->may_flags),
1016-
__entry->nf_ref, show_nf_flags(__entry->nf_flags),
1017-
show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
1018-
)
1019-
);
1020-
1021984
TRACE_EVENT(nfsd_file_insert_err,
1022985
TP_PROTO(
1023986
const struct svc_rqst *rqstp,
@@ -1079,8 +1042,8 @@ TRACE_EVENT(nfsd_file_cons_err,
10791042
)
10801043
);
10811044

1082-
TRACE_EVENT(nfsd_file_open,
1083-
TP_PROTO(struct nfsd_file *nf, __be32 status),
1045+
DECLARE_EVENT_CLASS(nfsd_file_open_class,
1046+
TP_PROTO(const struct nfsd_file *nf, __be32 status),
10841047
TP_ARGS(nf, status),
10851048
TP_STRUCT__entry(
10861049
__field(void *, nf_inode) /* cannot be dereferenced */
@@ -1104,6 +1067,17 @@ TRACE_EVENT(nfsd_file_open,
11041067
__entry->nf_file)
11051068
)
11061069

1070+
#define DEFINE_NFSD_FILE_OPEN_EVENT(name) \
1071+
DEFINE_EVENT(nfsd_file_open_class, name, \
1072+
TP_PROTO( \
1073+
const struct nfsd_file *nf, \
1074+
__be32 status \
1075+
), \
1076+
TP_ARGS(nf, status))
1077+
1078+
DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_open);
1079+
DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_opened);
1080+
11071081
TRACE_EVENT(nfsd_file_is_cached,
11081082
TP_PROTO(
11091083
const struct inode *inode,

0 commit comments

Comments
 (0)