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
This commit is contained in:
@@ -441,7 +441,10 @@ enum afs_lock_state {
|
||||
};
|
||||
|
||||
/*
|
||||
* AFS inode private data
|
||||
* AFS inode private data.
|
||||
*
|
||||
* Note that afs_alloc_inode() *must* reset anything that could incorrectly
|
||||
* leak from one inode to another.
|
||||
*/
|
||||
struct afs_vnode {
|
||||
struct inode vfs_inode; /* the VFS's inode record */
|
||||
|
||||
@@ -120,7 +120,7 @@ static void afs_hash_permits(struct afs_permits *permits)
|
||||
void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||
unsigned int cb_break)
|
||||
{
|
||||
struct afs_permits *permits, *xpermits, *replacement, *new = NULL;
|
||||
struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL;
|
||||
afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
|
||||
size_t size = 0;
|
||||
bool changed = false;
|
||||
@@ -204,7 +204,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||
new = kzalloc(sizeof(struct afs_permits) +
|
||||
sizeof(struct afs_permit) * size, GFP_NOFS);
|
||||
if (!new)
|
||||
return;
|
||||
goto out_put;
|
||||
|
||||
refcount_set(&new->usage, 1);
|
||||
new->nr_permits = size;
|
||||
@@ -229,8 +229,6 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||
|
||||
afs_hash_permits(new);
|
||||
|
||||
afs_put_permits(permits);
|
||||
|
||||
/* Now see if the permit list we want is actually already available */
|
||||
spin_lock(&afs_permits_lock);
|
||||
|
||||
@@ -262,11 +260,15 @@ found:
|
||||
kfree(new);
|
||||
|
||||
spin_lock(&vnode->lock);
|
||||
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break) ||
|
||||
permits != rcu_access_pointer(vnode->permit_cache))
|
||||
goto someone_else_changed_it_unlock;
|
||||
rcu_assign_pointer(vnode->permit_cache, replacement);
|
||||
zap = rcu_access_pointer(vnode->permit_cache);
|
||||
if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) &&
|
||||
zap == permits)
|
||||
rcu_assign_pointer(vnode->permit_cache, replacement);
|
||||
else
|
||||
zap = replacement;
|
||||
spin_unlock(&vnode->lock);
|
||||
afs_put_permits(zap);
|
||||
out_put:
|
||||
afs_put_permits(permits);
|
||||
return;
|
||||
|
||||
|
||||
@@ -536,7 +536,9 @@ static void afs_kill_super(struct super_block *sb)
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise an inode cache slab element prior to any use
|
||||
* Initialise an inode cache slab element prior to any use. Note that
|
||||
* afs_alloc_inode() *must* reset anything that could incorrectly leak from one
|
||||
* inode to another.
|
||||
*/
|
||||
static void afs_i_init_once(void *_vnode)
|
||||
{
|
||||
@@ -568,11 +570,21 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
|
||||
|
||||
atomic_inc(&afs_count_active_inodes);
|
||||
|
||||
/* Reset anything that shouldn't leak from one inode to the next. */
|
||||
memset(&vnode->fid, 0, sizeof(vnode->fid));
|
||||
memset(&vnode->status, 0, sizeof(vnode->status));
|
||||
|
||||
vnode->volume = NULL;
|
||||
vnode->lock_key = NULL;
|
||||
vnode->permit_cache = NULL;
|
||||
vnode->cb_interest = NULL;
|
||||
#ifdef CONFIG_AFS_FSCACHE
|
||||
vnode->cache = NULL;
|
||||
#endif
|
||||
|
||||
vnode->flags = 1 << AFS_VNODE_UNSET;
|
||||
vnode->cb_type = 0;
|
||||
vnode->lock_state = AFS_VNODE_LOCK_NONE;
|
||||
|
||||
_leave(" = %p", &vnode->vfs_inode);
|
||||
return &vnode->vfs_inode;
|
||||
|
||||
Reference in New Issue
Block a user