AFS fixes
-----BEGIN PGP SIGNATURE----- iQIVAwUAWiFCXfSw1s6N8H32AQLtWg/+OWWvsRVmxw3voxdd8jZhSizm9gig40KJ BN+nf8eEPniTZPfHhQyoYCdMSOJXm1xfEqAETVvrrPGcatDCbxsKfohZlCMOn0v5 WCEAdCDy8XBBW1HuCBIKZX85HY6UTNVFIVtP3E+IjoPBjsV+gqUvxUDVLSVH2VIH UDyLRtO0Pl9AQS5pshJ7LfCQkwBDiw9Y5lD8DSyq5eAfxgAUFYl4uwCP9/JzZYyp +jUW1QfWl9lKh9y//Iz89TSWkaidVYr7YtKptE9uRm0XtNUymh7t5cNJ3ao79P93 oMZOHHgysl4j5o386str2sVmH76hiWArY56RTjXHMEvtzaMfOn1EuDeszPeAveWU ZwAdzeeuDW29DsdjZ/Vl6REnbgeuhsnUkjZUZ+B8k/yCTSH+X1ClP/00Z2RmDsaj Tc8EvCcsDCqB8rAa1qGBjDWPCNy4nMhf4yOAAW8qP9eNw7tEYNWMrbhyEh2yXWgd 1dhcFFYjghXUlKLQvnXnRsUKUi2liOQrUk+wvKYtrL4N6XIdgZRp/hQlKgjpdYxn 71Qop+dbn1EuOyGkcgpNxM+MPONWEqhavoQ1KawQxFJsBwo2GguzJ78BegEA5BYq iCVFS4adBtPGjjhmnCEP7nGqeJEP517YevcMo7Oo8o2XUOHWva5v8xaAK+CisEVM IJWmOvzd6rg= =1krM -----END PGP SIGNATURE----- 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:
Коммит
ae753ee277
|
@ -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 afs_vnode {
|
||||||
struct inode vfs_inode; /* the VFS's inode record */
|
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,
|
void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||||
unsigned int cb_break)
|
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);
|
afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
@ -204,7 +204,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||||
new = kzalloc(sizeof(struct afs_permits) +
|
new = kzalloc(sizeof(struct afs_permits) +
|
||||||
sizeof(struct afs_permit) * size, GFP_NOFS);
|
sizeof(struct afs_permit) * size, GFP_NOFS);
|
||||||
if (!new)
|
if (!new)
|
||||||
return;
|
goto out_put;
|
||||||
|
|
||||||
refcount_set(&new->usage, 1);
|
refcount_set(&new->usage, 1);
|
||||||
new->nr_permits = size;
|
new->nr_permits = size;
|
||||||
|
@ -229,8 +229,6 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
|
||||||
|
|
||||||
afs_hash_permits(new);
|
afs_hash_permits(new);
|
||||||
|
|
||||||
afs_put_permits(permits);
|
|
||||||
|
|
||||||
/* Now see if the permit list we want is actually already available */
|
/* Now see if the permit list we want is actually already available */
|
||||||
spin_lock(&afs_permits_lock);
|
spin_lock(&afs_permits_lock);
|
||||||
|
|
||||||
|
@ -262,11 +260,15 @@ found:
|
||||||
kfree(new);
|
kfree(new);
|
||||||
|
|
||||||
spin_lock(&vnode->lock);
|
spin_lock(&vnode->lock);
|
||||||
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break) ||
|
zap = rcu_access_pointer(vnode->permit_cache);
|
||||||
permits != rcu_access_pointer(vnode->permit_cache))
|
if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) &&
|
||||||
goto someone_else_changed_it_unlock;
|
zap == permits)
|
||||||
rcu_assign_pointer(vnode->permit_cache, replacement);
|
rcu_assign_pointer(vnode->permit_cache, replacement);
|
||||||
|
else
|
||||||
|
zap = replacement;
|
||||||
spin_unlock(&vnode->lock);
|
spin_unlock(&vnode->lock);
|
||||||
|
afs_put_permits(zap);
|
||||||
|
out_put:
|
||||||
afs_put_permits(permits);
|
afs_put_permits(permits);
|
||||||
return;
|
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)
|
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);
|
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->fid, 0, sizeof(vnode->fid));
|
||||||
memset(&vnode->status, 0, sizeof(vnode->status));
|
memset(&vnode->status, 0, sizeof(vnode->status));
|
||||||
|
|
||||||
vnode->volume = NULL;
|
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->flags = 1 << AFS_VNODE_UNSET;
|
||||||
|
vnode->cb_type = 0;
|
||||||
|
vnode->lock_state = AFS_VNODE_LOCK_NONE;
|
||||||
|
|
||||||
_leave(" = %p", &vnode->vfs_inode);
|
_leave(" = %p", &vnode->vfs_inode);
|
||||||
return &vnode->vfs_inode;
|
return &vnode->vfs_inode;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче