Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
NFS: Fix RCU issues in the NFSv4 delegation code
NFSv4: Fix the locking in nfs_inode_reclaim_delegation()

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