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 tag 'afs-fixes-20171201' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull AFS fixes from David Howells:
"Two fix patches for the AFS filesystem:

- Fix the refcounting on permit caching.

- AFS inode (afs_vnode) fields need resetting after allocation
because they're only initialised when slab pages are obtained from
the page allocator"

* tag 'afs-fixes-20171201' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
afs: Properly reset afs_vnode (inode) fields
afs: Fix permit refcounting

+27 -10
+4 -1
fs/afs/internal.h
··· 441 441 }; 442 442 443 443 /* 444 - * AFS inode private data 444 + * AFS inode private data. 445 + * 446 + * Note that afs_alloc_inode() *must* reset anything that could incorrectly 447 + * leak from one inode to another. 445 448 */ 446 449 struct afs_vnode { 447 450 struct inode vfs_inode; /* the VFS's inode record */
+10 -8
fs/afs/security.c
··· 120 120 void afs_cache_permit(struct afs_vnode *vnode, struct key *key, 121 121 unsigned int cb_break) 122 122 { 123 - struct afs_permits *permits, *xpermits, *replacement, *new = NULL; 123 + struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL; 124 124 afs_access_t caller_access = READ_ONCE(vnode->status.caller_access); 125 125 size_t size = 0; 126 126 bool changed = false; ··· 204 204 new = kzalloc(sizeof(struct afs_permits) + 205 205 sizeof(struct afs_permit) * size, GFP_NOFS); 206 206 if (!new) 207 - return; 207 + goto out_put; 208 208 209 209 refcount_set(&new->usage, 1); 210 210 new->nr_permits = size; ··· 228 228 } 229 229 230 230 afs_hash_permits(new); 231 - 232 - afs_put_permits(permits); 233 231 234 232 /* Now see if the permit list we want is actually already available */ 235 233 spin_lock(&afs_permits_lock); ··· 260 262 kfree(new); 261 263 262 264 spin_lock(&vnode->lock); 263 - if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break) || 264 - permits != rcu_access_pointer(vnode->permit_cache)) 265 - goto someone_else_changed_it_unlock; 266 - rcu_assign_pointer(vnode->permit_cache, replacement); 265 + zap = rcu_access_pointer(vnode->permit_cache); 266 + if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) && 267 + zap == permits) 268 + rcu_assign_pointer(vnode->permit_cache, replacement); 269 + else 270 + zap = replacement; 267 271 spin_unlock(&vnode->lock); 272 + afs_put_permits(zap); 273 + out_put: 268 274 afs_put_permits(permits); 269 275 return; 270 276
+13 -1
fs/afs/super.c
··· 536 536 } 537 537 538 538 /* 539 - * initialise an inode cache slab element prior to any use 539 + * Initialise an inode cache slab element prior to any use. Note that 540 + * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 541 + * inode to another. 540 542 */ 541 543 static void afs_i_init_once(void *_vnode) 542 544 { ··· 570 568 571 569 atomic_inc(&afs_count_active_inodes); 572 570 571 + /* Reset anything that shouldn't leak from one inode to the next. */ 573 572 memset(&vnode->fid, 0, sizeof(vnode->fid)); 574 573 memset(&vnode->status, 0, sizeof(vnode->status)); 575 574 576 575 vnode->volume = NULL; 576 + vnode->lock_key = NULL; 577 + vnode->permit_cache = NULL; 578 + vnode->cb_interest = NULL; 579 + #ifdef CONFIG_AFS_FSCACHE 580 + vnode->cache = NULL; 581 + #endif 582 + 577 583 vnode->flags = 1 << AFS_VNODE_UNSET; 584 + vnode->cb_type = 0; 585 + vnode->lock_state = AFS_VNODE_LOCK_NONE; 578 586 579 587 _leave(" = %p", &vnode->vfs_inode); 580 588 return &vnode->vfs_inode;