24
24
25
25
static void nfs_do_free_delegation (struct nfs_delegation * delegation )
26
26
{
27
+ if (delegation -> cred )
28
+ put_rpccred (delegation -> cred );
27
29
kfree (delegation );
28
30
}
29
31
@@ -36,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head)
36
38
37
39
static void nfs_free_delegation (struct nfs_delegation * delegation )
38
40
{
39
- struct rpc_cred * cred ;
40
-
41
- cred = rcu_dereference (delegation -> cred );
42
- rcu_assign_pointer (delegation -> cred , NULL );
43
41
call_rcu (& delegation -> rcu , nfs_free_delegation_callback );
44
- if (cred )
45
- put_rpccred (cred );
46
42
}
47
43
48
44
void nfs_mark_delegation_referenced (struct nfs_delegation * delegation )
@@ -129,21 +125,35 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s
129
125
*/
130
126
void nfs_inode_reclaim_delegation (struct inode * inode , struct rpc_cred * cred , struct nfs_openres * res )
131
127
{
132
- struct nfs_delegation * delegation = NFS_I ( inode ) -> delegation ;
133
- struct rpc_cred * oldcred ;
128
+ struct nfs_delegation * delegation ;
129
+ struct rpc_cred * oldcred = NULL ;
134
130
135
- if (delegation == NULL )
136
- return ;
137
- memcpy (delegation -> stateid .data , res -> delegation .data ,
138
- sizeof (delegation -> stateid .data ));
139
- delegation -> type = res -> delegation_type ;
140
- delegation -> maxsize = res -> maxsize ;
141
- oldcred = delegation -> cred ;
142
- delegation -> cred = get_rpccred (cred );
143
- clear_bit (NFS_DELEGATION_NEED_RECLAIM , & delegation -> flags );
144
- NFS_I (inode )-> delegation_state = delegation -> type ;
145
- smp_wmb ();
146
- put_rpccred (oldcred );
131
+ rcu_read_lock ();
132
+ delegation = rcu_dereference (NFS_I (inode )-> delegation );
133
+ if (delegation != NULL ) {
134
+ spin_lock (& delegation -> lock );
135
+ if (delegation -> inode != NULL ) {
136
+ memcpy (delegation -> stateid .data , res -> delegation .data ,
137
+ sizeof (delegation -> stateid .data ));
138
+ delegation -> type = res -> delegation_type ;
139
+ delegation -> maxsize = res -> maxsize ;
140
+ oldcred = delegation -> cred ;
141
+ delegation -> cred = get_rpccred (cred );
142
+ clear_bit (NFS_DELEGATION_NEED_RECLAIM ,
143
+ & delegation -> flags );
144
+ NFS_I (inode )-> delegation_state = delegation -> type ;
145
+ spin_unlock (& delegation -> lock );
146
+ put_rpccred (oldcred );
147
+ rcu_read_unlock ();
148
+ } else {
149
+ /* We appear to have raced with a delegation return. */
150
+ spin_unlock (& delegation -> lock );
151
+ rcu_read_unlock ();
152
+ nfs_inode_set_delegation (inode , cred , res );
153
+ }
154
+ } else {
155
+ rcu_read_unlock ();
156
+ }
147
157
}
148
158
149
159
static int nfs_do_return_delegation (struct inode * inode , struct nfs_delegation * delegation , int issync )
@@ -166,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
166
176
return inode ;
167
177
}
168
178
169
- static struct nfs_delegation * nfs_detach_delegation_locked (struct nfs_inode * nfsi , const nfs4_stateid * stateid )
179
+ static struct nfs_delegation * nfs_detach_delegation_locked (struct nfs_inode * nfsi ,
180
+ const nfs4_stateid * stateid ,
181
+ struct nfs_client * clp )
170
182
{
171
- struct nfs_delegation * delegation = rcu_dereference (nfsi -> delegation );
183
+ struct nfs_delegation * delegation =
184
+ rcu_dereference_protected (nfsi -> delegation ,
185
+ lockdep_is_held (& clp -> cl_lock ));
172
186
173
187
if (delegation == NULL )
174
188
goto nomatch ;
@@ -195,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
195
209
{
196
210
struct nfs_client * clp = NFS_SERVER (inode )-> nfs_client ;
197
211
struct nfs_inode * nfsi = NFS_I (inode );
198
- struct nfs_delegation * delegation ;
212
+ struct nfs_delegation * delegation , * old_delegation ;
199
213
struct nfs_delegation * freeme = NULL ;
200
214
int status = 0 ;
201
215
@@ -213,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
213
227
spin_lock_init (& delegation -> lock );
214
228
215
229
spin_lock (& clp -> cl_lock );
216
- if (rcu_dereference (nfsi -> delegation ) != NULL ) {
217
- if (memcmp (& delegation -> stateid , & nfsi -> delegation -> stateid ,
218
- sizeof (delegation -> stateid )) == 0 &&
219
- delegation -> type == nfsi -> delegation -> type ) {
230
+ old_delegation = rcu_dereference_protected (nfsi -> delegation ,
231
+ lockdep_is_held (& clp -> cl_lock ));
232
+ if (old_delegation != NULL ) {
233
+ if (memcmp (& delegation -> stateid , & old_delegation -> stateid ,
234
+ sizeof (old_delegation -> stateid )) == 0 &&
235
+ delegation -> type == old_delegation -> type ) {
220
236
goto out ;
221
237
}
222
238
/*
@@ -226,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
226
242
dfprintk (FILE , "%s: server %s handed out "
227
243
"a duplicate delegation!\n" ,
228
244
__func__ , clp -> cl_hostname );
229
- if (delegation -> type <= nfsi -> delegation -> type ) {
245
+ if (delegation -> type <= old_delegation -> type ) {
230
246
freeme = delegation ;
231
247
delegation = NULL ;
232
248
goto out ;
233
249
}
234
- freeme = nfs_detach_delegation_locked (nfsi , NULL );
250
+ freeme = nfs_detach_delegation_locked (nfsi , NULL , clp );
235
251
}
236
252
list_add_rcu (& delegation -> super_list , & clp -> cl_delegations );
237
253
nfsi -> delegation_state = delegation -> type ;
@@ -301,7 +317,7 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp)
301
317
if (inode == NULL )
302
318
continue ;
303
319
spin_lock (& clp -> cl_lock );
304
- delegation = nfs_detach_delegation_locked (NFS_I (inode ), NULL );
320
+ delegation = nfs_detach_delegation_locked (NFS_I (inode ), NULL , clp );
305
321
spin_unlock (& clp -> cl_lock );
306
322
rcu_read_unlock ();
307
323
if (delegation != NULL ) {
@@ -330,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
330
346
struct nfs_inode * nfsi = NFS_I (inode );
331
347
struct nfs_delegation * delegation ;
332
348
333
- if (rcu_dereference (nfsi -> delegation ) != NULL ) {
349
+ if (rcu_access_pointer (nfsi -> delegation ) != NULL ) {
334
350
spin_lock (& clp -> cl_lock );
335
- delegation = nfs_detach_delegation_locked (nfsi , NULL );
351
+ delegation = nfs_detach_delegation_locked (nfsi , NULL , clp );
336
352
spin_unlock (& clp -> cl_lock );
337
353
if (delegation != NULL )
338
354
nfs_do_return_delegation (inode , delegation , 0 );
@@ -346,9 +362,9 @@ int nfs_inode_return_delegation(struct inode *inode)
346
362
struct nfs_delegation * delegation ;
347
363
int err = 0 ;
348
364
349
- if (rcu_dereference (nfsi -> delegation ) != NULL ) {
365
+ if (rcu_access_pointer (nfsi -> delegation ) != NULL ) {
350
366
spin_lock (& clp -> cl_lock );
351
- delegation = nfs_detach_delegation_locked (nfsi , NULL );
367
+ delegation = nfs_detach_delegation_locked (nfsi , NULL , clp );
352
368
spin_unlock (& clp -> cl_lock );
353
369
if (delegation != NULL ) {
354
370
nfs_msync_inode (inode );
@@ -526,7 +542,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
526
542
if (inode == NULL )
527
543
continue ;
528
544
spin_lock (& clp -> cl_lock );
529
- delegation = nfs_detach_delegation_locked (NFS_I (inode ), NULL );
545
+ delegation = nfs_detach_delegation_locked (NFS_I (inode ), NULL , clp );
530
546
spin_unlock (& clp -> cl_lock );
531
547
rcu_read_unlock ();
532
548
if (delegation != NULL )
0 commit comments