• Omar Sandoval's avatar
    Btrfs: don't invalidate root dentry when subvolume deletion fails · 64ad6c48
    Omar Sandoval authored
    Since commit bafc9b75 ("vfs: More precise tests in d_invalidate"),
    mounted subvolumes can be deleted because d_invalidate() won't fail.
    However, we run into problems when we attempt to delete the default
    subvolume while it is mounted as the root filesystem:
    
    	# btrfs subvol list /
    	ID 257 gen 306 top level 5 path rootvol
    	ID 267 gen 334 top level 5 path snap1
    	# btrfs subvol get-default /
    	ID 267 gen 334 top level 5 path snap1
    	# btrfs inspect-internal rootid /
    	267
    	# mount -o subvol=/ /dev/vda1 /mnt
    	# btrfs subvol del /mnt/snap1
    	Delete subvolume (no-commit): '/mnt/snap1'
    	ERROR: cannot delete '/mnt/snap1' - Operation not permitted
    	# findmnt /
    	findmnt: can't read /proc/mounts: No such file or directory
    	# ls /proc
    	#
    
    Markus reported that this same scenario simply led to a kernel oops.
    
    This happens because in btrfs_ioctl_snap_destroy(), we call
    d_invalidate() before we check may_destroy_subvol(), which means that we
    detach the submounts and drop the dentry before erroring out. Instead,
    we should only invalidate the dentry once the deletion has succeeded.
    Additionally, the shrink_dcache_sb() isn't necessary; d_invalidate()
    will prune the dcache for the deleted subvolume.
    
    Cc: <stable@vger.kernel.org>
    Fixes: bafc9b75 ("vfs: More precise tests in d_invalidate")
    Reported-by: default avatarMarkus Schauler <mschauler@gmail.com>
    Signed-off-by: default avatarOmar Sandoval <osandov@osandov.com>
    Signed-off-by: default avatarChris Mason <clm@fb.com>
    64ad6c48
ioctl.c 129 KB