aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-12-01 08:36:27 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-12-01 08:36:27 -0500
commitae753ee2771a1bacade56411bb98037b2545c929 (patch)
tree51bd6c507272f03ace4da537f531029785e69cb5
parent3c1c4ddffb58b9e10b3365764fe59546130b3f32 (diff)
parentf8de483e7440b0d23ce6372b3ef8358841c8827b (diff)
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
-rw-r--r--fs/afs/internal.h5
-rw-r--r--fs/afs/security.c18
-rw-r--r--fs/afs/super.c14
3 files changed, 27 insertions, 10 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index e03910cebdd4..804d1f905622 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -441,7 +441,10 @@ enum afs_lock_state {
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 */
446struct afs_vnode { 449struct afs_vnode {
447 struct inode vfs_inode; /* the VFS's inode record */ 450 struct inode vfs_inode; /* the VFS's inode record */
diff --git a/fs/afs/security.c b/fs/afs/security.c
index 2b00097101b3..b88b7d45fdaa 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -120,7 +120,7 @@ static void afs_hash_permits(struct afs_permits *permits)
120void afs_cache_permit(struct afs_vnode *vnode, struct key *key, 120void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
121 unsigned int cb_break) 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 afs_access_t caller_access = READ_ONCE(vnode->status.caller_access); 124 afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
125 size_t size = 0; 125 size_t size = 0;
126 bool changed = false; 126 bool changed = false;
@@ -204,7 +204,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
204 new = kzalloc(sizeof(struct afs_permits) + 204 new = kzalloc(sizeof(struct afs_permits) +
205 sizeof(struct afs_permit) * size, GFP_NOFS); 205 sizeof(struct afs_permit) * size, GFP_NOFS);
206 if (!new) 206 if (!new)
207 return; 207 goto out_put;
208 208
209 refcount_set(&new->usage, 1); 209 refcount_set(&new->usage, 1);
210 new->nr_permits = size; 210 new->nr_permits = size;
@@ -229,8 +229,6 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
229 229
230 afs_hash_permits(new); 230 afs_hash_permits(new);
231 231
232 afs_put_permits(permits);
233
234 /* Now see if the permit list we want is actually already available */ 232 /* Now see if the permit list we want is actually already available */
235 spin_lock(&afs_permits_lock); 233 spin_lock(&afs_permits_lock);
236 234
@@ -262,11 +260,15 @@ found:
262 kfree(new); 260 kfree(new);
263 261
264 spin_lock(&vnode->lock); 262 spin_lock(&vnode->lock);
265 if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break) || 263 zap = rcu_access_pointer(vnode->permit_cache);
266 permits != rcu_access_pointer(vnode->permit_cache)) 264 if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) &&
267 goto someone_else_changed_it_unlock; 265 zap == permits)
268 rcu_assign_pointer(vnode->permit_cache, replacement); 266 rcu_assign_pointer(vnode->permit_cache, replacement);
267 else
268 zap = replacement;
269 spin_unlock(&vnode->lock); 269 spin_unlock(&vnode->lock);
270 afs_put_permits(zap);
271out_put:
270 afs_put_permits(permits); 272 afs_put_permits(permits);
271 return; 273 return;
272 274
diff --git a/fs/afs/super.c b/fs/afs/super.c
index d3f97da61bdf..1037dd41a622 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -536,7 +536,9 @@ static void afs_kill_super(struct super_block *sb)
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 */
541static void afs_i_init_once(void *_vnode) 543static void afs_i_init_once(void *_vnode)
542{ 544{
@@ -568,11 +570,21 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
568 570
569 atomic_inc(&afs_count_active_inodes); 571 atomic_inc(&afs_count_active_inodes);
570 572
573 /* Reset anything that shouldn't leak from one inode to the next. */
571 memset(&vnode->fid, 0, sizeof(vnode->fid)); 574 memset(&vnode->fid, 0, sizeof(vnode->fid));
572 memset(&vnode->status, 0, sizeof(vnode->status)); 575 memset(&vnode->status, 0, sizeof(vnode->status));
573 576
574 vnode->volume = NULL; 577 vnode->volume = NULL;
578 vnode->lock_key = NULL;
579 vnode->permit_cache = NULL;
580 vnode->cb_interest = NULL;
581#ifdef CONFIG_AFS_FSCACHE
582 vnode->cache = NULL;
583#endif
584
575 vnode->flags = 1 << AFS_VNODE_UNSET; 585 vnode->flags = 1 << AFS_VNODE_UNSET;
586 vnode->cb_type = 0;
587 vnode->lock_state = AFS_VNODE_LOCK_NONE;
576 588
577 _leave(" = %p", &vnode->vfs_inode); 589 _leave(" = %p", &vnode->vfs_inode);
578 return &vnode->vfs_inode; 590 return &vnode->vfs_inode;