Skip to content

Commit e6f7e14

Browse files
neilbrownAnna Schumaker
authored andcommitted
nfs_localio: simplify interface to nfsd for getting nfsd_file
The nfsd_localio_operations structure contains nfsd_file_get() to get a reference to an nfsd_file. This is only used in one place, where nfsd_open_local_fh() is also used. This patch combines the two, calling nfsd_open_local_fh() passing a pointer to where the nfsd_file pointer might be stored. If there is a pointer there an nfsd_file_get() can get a reference, that reference is returned. If not a new nfsd_file is acquired, stored at the pointer, and returned. When we store a reference we also increase the refcount on the net, as that refcount is decrements when we clear the stored pointer. We now get an extra reference *before* storing the new nfsd_file at the given location. This avoids possible races with the nfsd_file being freed before the final reference can be taken. This patch moves the rcu_dereference() needed after fetching from ro_file or rw_file into the nfsd code where the 'struct nfs_file' is fully defined. This avoids an error reported by older versions of gcc such as gcc-8 which complain about rcu_dereference() use in contexts where the structure (which will supposedly be accessed) is not fully defined. Reported-by: Pali Rohár <[email protected]> Reported-by: Vincent Mailhol <[email protected]> Fixes: 86e0041 ("nfs: cache all open LOCALIO nfsd_file(s) in client") Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 77e82fb commit e6f7e14

File tree

3 files changed

+55
-44
lines changed

3 files changed

+55
-44
lines changed

fs/nfs/localio.c

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,6 @@ void nfs_local_probe_async(struct nfs_client *clp)
209209
}
210210
EXPORT_SYMBOL_GPL(nfs_local_probe_async);
211211

212-
static inline struct nfsd_file *nfs_local_file_get(struct nfsd_file *nf)
213-
{
214-
return nfs_to->nfsd_file_get_local(nf);
215-
}
216-
217212
static inline void nfs_local_file_put(struct nfsd_file *nf)
218213
{
219214
nfs_to_nfsd_file_put_local(nf);
@@ -228,12 +223,13 @@ static inline void nfs_local_file_put(struct nfsd_file *nf)
228223
static struct nfsd_file *
229224
__nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
230225
struct nfs_fh *fh, struct nfs_file_localio *nfl,
226+
struct nfsd_file __rcu **pnf,
231227
const fmode_t mode)
232228
{
233229
struct nfsd_file *localio;
234230

235231
localio = nfs_open_local_fh(&clp->cl_uuid, clp->cl_rpcclient,
236-
cred, fh, nfl, mode);
232+
cred, fh, nfl, pnf, mode);
237233
if (IS_ERR(localio)) {
238234
int status = PTR_ERR(localio);
239235
trace_nfs_local_open_fh(fh, mode, status);
@@ -260,7 +256,7 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
260256
struct nfs_fh *fh, struct nfs_file_localio *nfl,
261257
const fmode_t mode)
262258
{
263-
struct nfsd_file *nf, *new, __rcu **pnf;
259+
struct nfsd_file *nf, __rcu **pnf;
264260

265261
if (!nfs_server_is_local(clp))
266262
return NULL;
@@ -272,24 +268,9 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
272268
else
273269
pnf = &nfl->ro_file;
274270

275-
new = NULL;
276-
rcu_read_lock();
277-
nf = rcu_dereference(*pnf);
278-
if (!nf) {
279-
rcu_read_unlock();
280-
new = __nfs_local_open_fh(clp, cred, fh, nfl, mode);
281-
if (IS_ERR(new))
282-
return NULL;
283-
rcu_read_lock();
284-
/* try to swap in the pointer */
285-
nf = unrcu_pointer(cmpxchg(pnf, NULL, RCU_INITIALIZER(new)));
286-
if (!nf)
287-
swap(nf, new);
288-
}
289-
nf = nfs_local_file_get(nf);
290-
rcu_read_unlock();
291-
if (new)
292-
nfs_to_nfsd_file_put_local(new);
271+
nf = __nfs_local_open_fh(clp, cred, fh, nfl, pnf, mode);
272+
if (IS_ERR(nf))
273+
return NULL;
293274
return nf;
294275
}
295276
EXPORT_SYMBOL_GPL(nfs_local_open_fh);

fs/nfs_common/nfslocalio.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ static void nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl
237237
struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
238238
struct rpc_clnt *rpc_clnt, const struct cred *cred,
239239
const struct nfs_fh *nfs_fh, struct nfs_file_localio *nfl,
240+
struct nfsd_file __rcu **pnf,
240241
const fmode_t fmode)
241242
{
242243
struct net *net;
@@ -261,7 +262,7 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
261262
rcu_read_unlock();
262263
/* We have an implied reference to net thanks to nfsd_net_try_get */
263264
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
264-
cred, nfs_fh, fmode);
265+
cred, nfs_fh, pnf, fmode);
265266
nfs_to_nfsd_net_put(net);
266267
if (!IS_ERR(localio))
267268
nfs_uuid_add_file(uuid, nfl);

fs/nfsd/localio.c

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,6 @@
2424
#include "filecache.h"
2525
#include "cache.h"
2626

27-
static const struct nfsd_localio_operations nfsd_localio_ops = {
28-
.nfsd_net_try_get = nfsd_net_try_get,
29-
.nfsd_net_put = nfsd_net_put,
30-
.nfsd_open_local_fh = nfsd_open_local_fh,
31-
.nfsd_file_put_local = nfsd_file_put_local,
32-
.nfsd_file_get_local = nfsd_file_get_local,
33-
.nfsd_file_file = nfsd_file_file,
34-
};
35-
36-
void nfsd_localio_ops_init(void)
37-
{
38-
nfs_to = &nfsd_localio_ops;
39-
}
40-
4127
/**
4228
* nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
4329
*
@@ -46,6 +32,7 @@ void nfsd_localio_ops_init(void)
4632
* @rpc_clnt: rpc_clnt that the client established
4733
* @cred: cred that the client established
4834
* @nfs_fh: filehandle to lookup
35+
* @nfp: place to find the nfsd_file, or store it if it was non-NULL
4936
* @fmode: fmode_t to use for open
5037
*
5138
* This function maps a local fh to a path on a local filesystem.
@@ -56,10 +43,11 @@ void nfsd_localio_ops_init(void)
5643
* set. Caller (NFS client) is responsible for calling nfsd_net_put and
5744
* nfsd_file_put (via nfs_to_nfsd_file_put_local).
5845
*/
59-
struct nfsd_file *
46+
static struct nfsd_file *
6047
nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
6148
struct rpc_clnt *rpc_clnt, const struct cred *cred,
62-
const struct nfs_fh *nfs_fh, const fmode_t fmode)
49+
const struct nfs_fh *nfs_fh, struct nfsd_file __rcu **pnf,
50+
const fmode_t fmode)
6351
{
6452
int mayflags = NFSD_MAY_LOCALIO;
6553
struct svc_cred rq_cred;
@@ -73,6 +61,12 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
7361
if (!nfsd_net_try_get(net))
7462
return ERR_PTR(-ENXIO);
7563

64+
rcu_read_lock();
65+
localio = nfsd_file_get(rcu_dereference(*pnf));
66+
rcu_read_unlock();
67+
if (localio)
68+
return localio;
69+
7670
/* nfs_fh -> svc_fh */
7771
fh_init(&fh, NFS4_FHSIZE);
7872
fh.fh_handle.fh_size = nfs_fh->size;
@@ -94,12 +88,47 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
9488
if (rq_cred.cr_group_info)
9589
put_group_info(rq_cred.cr_group_info);
9690

97-
if (IS_ERR(localio))
91+
if (!IS_ERR(localio)) {
92+
struct nfsd_file *new;
93+
if (!nfsd_net_try_get(net)) {
94+
nfsd_file_put(localio);
95+
nfsd_net_put(net);
96+
return ERR_PTR(-ENXIO);
97+
}
98+
nfsd_file_get(localio);
99+
again:
100+
new = unrcu_pointer(cmpxchg(pnf, NULL, RCU_INITIALIZER(localio)));
101+
if (new) {
102+
/* Some other thread installed an nfsd_file */
103+
if (nfsd_file_get(new) == NULL)
104+
goto again;
105+
/*
106+
* Drop the ref we were going to install and the
107+
* one we were going to return.
108+
*/
109+
nfsd_file_put(localio);
110+
nfsd_file_put(localio);
111+
localio = new;
112+
}
113+
} else
98114
nfsd_net_put(net);
99115

100116
return localio;
101117
}
102-
EXPORT_SYMBOL_GPL(nfsd_open_local_fh);
118+
119+
static const struct nfsd_localio_operations nfsd_localio_ops = {
120+
.nfsd_net_try_get = nfsd_net_try_get,
121+
.nfsd_net_put = nfsd_net_put,
122+
.nfsd_open_local_fh = nfsd_open_local_fh,
123+
.nfsd_file_put_local = nfsd_file_put_local,
124+
.nfsd_file_get_local = nfsd_file_get_local,
125+
.nfsd_file_file = nfsd_file_file,
126+
};
127+
128+
void nfsd_localio_ops_init(void)
129+
{
130+
nfs_to = &nfsd_localio_ops;
131+
}
103132

104133
/*
105134
* UUID_IS_LOCAL XDR functions

0 commit comments

Comments
 (0)