mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 06:17:27 +02:00
afs: Fix double-unmap of directory block
Fix afs_edit_dir_remove() to use a cleanup function to unmap the block
pointed to by afs_dir_iter::block if it's left pointing to something rather
than manually kunmapping the blocks. Manually kunmapping without clearing
iter.blocks can result in a double-kunmap if afs_dir_find_block() is called
twice in a row (which would be the case if the block being modified is not
first in the hash chain).
Fixes: a5b5beebcf ("afs: Use the contained hashtable to search a directory")
Closes: https://sashiko.dev/#/patchset/20260716103030.3065561-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260902121024.3328255-3-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
cc: linux-fsdevel@vger.kernel.org
cc: stable@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
parent
950ae84b5c
commit
e3cfd3eb7d
|
|
@ -442,7 +442,7 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
|||
/* Check and clear the entry. */
|
||||
de = &block->dirents[slot];
|
||||
if (de->u.valid != 1)
|
||||
goto error_unmap;
|
||||
goto error;
|
||||
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_delete, b, slot,
|
||||
ntohl(de->u.vnode), ntohl(de->u.unique),
|
||||
|
|
@ -458,7 +458,6 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
|||
/* Clear the constituent entries. */
|
||||
next = de->u.hash_next;
|
||||
memset(de, 0, sizeof(*de) * iter.nr_slots);
|
||||
kunmap_local(block);
|
||||
|
||||
/* Adjust the hash chain: if iter->prev_entry is 0, the hashtable head
|
||||
* index is previous; otherwise it's slot number of the previous entry.
|
||||
|
|
@ -485,7 +484,6 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
|||
pde = &pblock->dirents[ps];
|
||||
prev_next = pde->u.hash_next;
|
||||
if (prev_next != htons(entry)) {
|
||||
kunmap_local(pblock);
|
||||
pr_warn("%llx:%llx:%x: not prev in chain b=%x p=%x,%x e=%x %*s",
|
||||
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
|
||||
iter.bucket, iter.prev_entry, prev_next, entry,
|
||||
|
|
@ -493,7 +491,6 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
|||
goto error;
|
||||
}
|
||||
pde->u.hash_next = next;
|
||||
kunmap_local(pblock);
|
||||
}
|
||||
|
||||
netfs_single_mark_inode_dirty(&vnode->netfs.inode);
|
||||
|
|
@ -503,18 +500,16 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
|||
_debug("Remove %s from %u[%u]", name->name, b, slot);
|
||||
|
||||
out_unmap:
|
||||
afs_dir_end_iter(&iter);
|
||||
kunmap_local(meta);
|
||||
_leave("");
|
||||
return;
|
||||
|
||||
already_invalidated:
|
||||
kunmap_local(block);
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval,
|
||||
0, 0, 0, 0, name->name);
|
||||
goto out_unmap;
|
||||
|
||||
error_unmap:
|
||||
kunmap_local(block);
|
||||
error:
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_error,
|
||||
0, 0, 0, 0, name->name);
|
||||
|
|
|
|||
|
|
@ -75,10 +75,7 @@ union afs_xdr_dir_block *afs_dir_find_block(struct afs_dir_iter *iter, size_t bl
|
|||
|
||||
_enter("%zx,%d", block, slot);
|
||||
|
||||
if (iter->block) {
|
||||
kunmap_local(iter->block);
|
||||
iter->block = NULL;
|
||||
}
|
||||
afs_dir_end_iter(iter);
|
||||
|
||||
if (dvnode->directory_size < blend)
|
||||
goto fail;
|
||||
|
|
@ -174,10 +171,7 @@ int afs_dir_search_bucket(struct afs_dir_iter *iter, const struct qstr *name,
|
|||
ret = -ENOENT;
|
||||
found:
|
||||
bad:
|
||||
if (iter->block) {
|
||||
kunmap_local(iter->block);
|
||||
iter->block = NULL;
|
||||
}
|
||||
afs_dir_end_iter(iter);
|
||||
if (ret == -ESTALE)
|
||||
afs_invalidate_dir(iter->dvnode, afs_dir_invalid_iter_stale);
|
||||
_leave(" = %d", ret);
|
||||
|
|
|
|||
|
|
@ -1133,6 +1133,14 @@ int afs_dir_search_bucket(struct afs_dir_iter *iter, const struct qstr *name,
|
|||
int afs_dir_search(struct afs_vnode *dvnode, const struct qstr *name,
|
||||
struct afs_fid *_fid, afs_dataversion_t *_dir_version);
|
||||
|
||||
static inline void afs_dir_end_iter(struct afs_dir_iter *iter)
|
||||
{
|
||||
if (iter->block) {
|
||||
kunmap_local(iter->block);
|
||||
iter->block = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dir_silly.c
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user