Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae753ee2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 3c1c4ddf f8de483e
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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 */
+10 −8
Original line number Diff line number Diff line
@@ -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 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
	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;
	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;

+13 −1
Original line number Diff line number Diff line
@@ -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;