Skip to content

Commit c25a897

Browse files
neilbrownAnna Schumaker
authored andcommitted
nfs_localio: change nfsd_file_put_local() to take a pointer to __rcu pointer
Instead of calling xchg() and unrcu_pointer() before nfsd_file_put_local(), we now pass pointer to the __rcu pointer and call xchg() and unrcu_pointer() inside that function. Where unrcu_pointer() is currently called the internals of "struct nfsd_file" are not known and that causes older compilers such as gcc-8 to complain. In some cases we have a __kernel (aka normal) pointer not an __rcu pointer so we need to cast it to __rcu first. This is strictly a weakening so no information is lost. Somewhat surprisingly, this cast is accepted by gcc-8. This has the pleasing result that the cmpxchg() which sets ro_file and rw_file, and also the xchg() which clears them, are both now in the nfsd code. 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 21fb440 commit c25a897

File tree

5 files changed

+36
-35
lines changed

5 files changed

+36
-35
lines changed

fs/nfs/localio.c

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

212-
static inline void nfs_local_file_put(struct nfsd_file *nf)
212+
static inline void nfs_local_file_put(struct nfsd_file *localio)
213213
{
214-
nfs_to_nfsd_file_put_local(nf);
214+
/* nfs_to_nfsd_file_put_local() expects an __rcu pointer
215+
* but we have a __kernel pointer. It is always safe
216+
* to cast a __kernel pointer to an __rcu pointer
217+
* because the cast only weakens what is known about the pointer.
218+
*/
219+
struct nfsd_file __rcu *nf = (struct nfsd_file __rcu*) localio;
220+
221+
nfs_to_nfsd_file_put_local(&nf);
215222
}
216223

217224
/*

fs/nfs_common/nfslocalio.c

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,6 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
170170
while ((nfl = list_first_entry_or_null(&nfs_uuid->files,
171171
struct nfs_file_localio,
172172
list)) != NULL) {
173-
struct nfsd_file *ro_nf;
174-
struct nfsd_file *rw_nf;
175-
176173
/* If nfs_uuid is already NULL, nfs_close_local_fh is
177174
* closing and we must wait, else we unlink and close.
178175
*/
@@ -189,17 +186,14 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
189186
continue;
190187
}
191188

192-
ro_nf = unrcu_pointer(xchg(&nfl->ro_file, NULL));
193-
rw_nf = unrcu_pointer(xchg(&nfl->rw_file, NULL));
194-
195189
/* Remove nfl from nfs_uuid->files list */
196190
list_del_init(&nfl->list);
197191
spin_unlock(&nfs_uuid->lock);
198-
if (ro_nf)
199-
nfs_to_nfsd_file_put_local(ro_nf);
200-
if (rw_nf)
201-
nfs_to_nfsd_file_put_local(rw_nf);
192+
193+
nfs_to_nfsd_file_put_local(&nfl->ro_file);
194+
nfs_to_nfsd_file_put_local(&nfl->rw_file);
202195
cond_resched();
196+
203197
spin_lock(&nfs_uuid->lock);
204198
/* Now we can allow racing nfs_close_local_fh() to
205199
* skip the locking.
@@ -303,8 +297,6 @@ EXPORT_SYMBOL_GPL(nfs_open_local_fh);
303297

304298
void nfs_close_local_fh(struct nfs_file_localio *nfl)
305299
{
306-
struct nfsd_file *ro_nf;
307-
struct nfsd_file *rw_nf;
308300
nfs_uuid_t *nfs_uuid;
309301

310302
rcu_read_lock();
@@ -337,12 +329,8 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
337329
spin_unlock(&nfs_uuid->lock);
338330
rcu_read_unlock();
339331

340-
ro_nf = unrcu_pointer(xchg(&nfl->ro_file, NULL));
341-
rw_nf = unrcu_pointer(xchg(&nfl->rw_file, NULL));
342-
if (ro_nf)
343-
nfs_to_nfsd_file_put_local(ro_nf);
344-
if (rw_nf)
345-
nfs_to_nfsd_file_put_local(rw_nf);
332+
nfs_to_nfsd_file_put_local(&nfl->ro_file);
333+
nfs_to_nfsd_file_put_local(&nfl->rw_file);
346334

347335
/* Remove nfl from nfs_uuid->files list and signal nfs_uuid_put()
348336
* that we are done. The moment we drop the spinlock the

fs/nfsd/filecache.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,16 @@ nfsd_file_put(struct nfsd_file *nf)
378378
* the reference of the nfsd_file.
379379
*/
380380
struct net *
381-
nfsd_file_put_local(struct nfsd_file *nf)
381+
nfsd_file_put_local(struct nfsd_file __rcu **pnf)
382382
{
383-
struct net *net = nf->nf_net;
383+
struct nfsd_file *nf;
384+
struct net *net = NULL;
384385

385-
nfsd_file_put(nf);
386+
nf = unrcu_pointer(xchg(pnf, NULL));
387+
if (nf) {
388+
net = nf->nf_net;
389+
nfsd_file_put(nf);
390+
}
386391
return net;
387392
}
388393

fs/nfsd/filecache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ void nfsd_file_cache_shutdown(void);
6262
int nfsd_file_cache_start_net(struct net *net);
6363
void nfsd_file_cache_shutdown_net(struct net *net);
6464
void nfsd_file_put(struct nfsd_file *nf);
65-
struct net *nfsd_file_put_local(struct nfsd_file *nf);
65+
struct net *nfsd_file_put_local(struct nfsd_file __rcu **nf);
6666
struct nfsd_file *nfsd_file_get_local(struct nfsd_file *nf);
6767
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
6868
struct file *nfsd_file_file(struct nfsd_file *nf);

include/linux/nfslocalio.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
5050
spinlock_t *nn_local_clients_lock);
5151

5252
/* localio needs to map filehandle -> struct nfsd_file */
53-
extern struct nfsd_file *
54-
nfsd_open_local_fh(struct net *, struct auth_domain *, struct rpc_clnt *,
55-
const struct cred *, const struct nfs_fh *,
56-
const fmode_t) __must_hold(rcu);
5753
void nfs_close_local_fh(struct nfs_file_localio *);
5854

5955
struct nfsd_localio_operations {
@@ -64,8 +60,9 @@ struct nfsd_localio_operations {
6460
struct rpc_clnt *,
6561
const struct cred *,
6662
const struct nfs_fh *,
63+
struct nfsd_file __rcu **pnf,
6764
const fmode_t);
68-
struct net *(*nfsd_file_put_local)(struct nfsd_file *);
65+
struct net *(*nfsd_file_put_local)(struct nfsd_file __rcu **);
6966
struct nfsd_file *(*nfsd_file_get_local)(struct nfsd_file *);
7067
struct file *(*nfsd_file_file)(struct nfsd_file *);
7168
} ____cacheline_aligned;
@@ -76,6 +73,7 @@ extern const struct nfsd_localio_operations *nfs_to;
7673
struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *,
7774
struct rpc_clnt *, const struct cred *,
7875
const struct nfs_fh *, struct nfs_file_localio *,
76+
struct nfsd_file __rcu **pnf,
7977
const fmode_t);
8078

8179
static inline void nfs_to_nfsd_net_put(struct net *net)
@@ -90,16 +88,19 @@ static inline void nfs_to_nfsd_net_put(struct net *net)
9088
rcu_read_unlock();
9189
}
9290

93-
static inline void nfs_to_nfsd_file_put_local(struct nfsd_file *localio)
91+
static inline void nfs_to_nfsd_file_put_local(struct nfsd_file __rcu **localio)
9492
{
9593
/*
96-
* Must not hold RCU otherwise nfsd_file_put() can easily trigger:
97-
* "Voluntary context switch within RCU read-side critical section!"
98-
* by scheduling deep in underlying filesystem (e.g. XFS).
94+
* Either *localio must be guaranteed to be non-NULL, or caller
95+
* must prevent nfsd shutdown from completing as nfs_close_local_fh()
96+
* does by blocking the nfs_uuid from being finally put.
9997
*/
100-
struct net *net = nfs_to->nfsd_file_put_local(localio);
98+
struct net *net;
10199

102-
nfs_to_nfsd_net_put(net);
100+
net = nfs_to->nfsd_file_put_local(localio);
101+
102+
if (net)
103+
nfs_to_nfsd_net_put(net);
103104
}
104105

105106
#else /* CONFIG_NFS_LOCALIO */

0 commit comments

Comments
 (0)