summaryrefslogtreecommitdiffstats
path: root/drivers/dax/super.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2017-06-09 17:50:49 +0200
committerDan Williams <dan.j.williams@intel.com>2017-06-09 17:50:49 +0200
commitb9d39d17e4819ca2e69ad1f14acaad12240a1de5 (patch)
tree53b1bebbf4d3c9c0303e70b1549795f4111e5462 /drivers/dax/super.c
parentLinux 4.12-rc4 (diff)
downloadlinux-b9d39d17e4819ca2e69ad1f14acaad12240a1de5.tar.xz
linux-b9d39d17e4819ca2e69ad1f14acaad12240a1de5.zip
device-dax: fix 'dax' device filesystem inode destruction crash
The inode destruction path for the 'dax' device filesystem incorrectly assumes that the inode was initialized through 'alloc_dax()'. However, if someone attempts to directly mount the dax filesystem with 'mount -t dax dax mnt' that will bypass 'alloc_dax()' and the following failure signatures may occur as a result: kill_dax() must be called before final iput() WARNING: CPU: 2 PID: 1188 at drivers/dax/super.c:243 dax_destroy_inode+0x48/0x50 RIP: 0010:dax_destroy_inode+0x48/0x50 Call Trace: destroy_inode+0x3b/0x60 evict+0x139/0x1c0 iput+0x1f9/0x2d0 dentry_unlink_inode+0xc3/0x160 __dentry_kill+0xcf/0x180 ? dput+0x37/0x3b0 dput+0x3a3/0x3b0 do_one_tree+0x36/0x40 shrink_dcache_for_umount+0x2d/0x90 generic_shutdown_super+0x1f/0x120 kill_anon_super+0x12/0x20 deactivate_locked_super+0x43/0x70 deactivate_super+0x4e/0x60 general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC RIP: 0010:kfree+0x6d/0x290 Call Trace: <IRQ> dax_i_callback+0x22/0x60 ? dax_destroy_inode+0x50/0x50 rcu_process_callbacks+0x298/0x740 ida_remove called for id=0 which is not allocated. WARNING: CPU: 0 PID: 0 at lib/idr.c:383 ida_remove+0x110/0x120 [..] Call Trace: <IRQ> ida_simple_remove+0x2b/0x50 ? dax_destroy_inode+0x50/0x50 dax_i_callback+0x3c/0x60 rcu_process_callbacks+0x298/0x740 Add missing initialization of the 'struct dax_device' and inode so that the destruction path does not kfree() or ida_simple_remove() uninitialized data. Fixes: 7b6be8444e0f ("dax: refactor dax-fs into a generic provider of 'struct dax_device' instances") Reported-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dax/super.c')
-rw-r--r--drivers/dax/super.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/dax/super.c b/drivers/dax/super.c
index 6ed32aac8bbe..922d0823f8ec 100644
--- a/drivers/dax/super.c
+++ b/drivers/dax/super.c
@@ -210,9 +210,12 @@ EXPORT_SYMBOL_GPL(kill_dax);
static struct inode *dax_alloc_inode(struct super_block *sb)
{
struct dax_device *dax_dev;
+ struct inode *inode;
dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL);
- return &dax_dev->inode;
+ inode = &dax_dev->inode;
+ inode->i_rdev = 0;
+ return inode;
}
static struct dax_device *to_dax_dev(struct inode *inode)
@@ -227,7 +230,8 @@ static void dax_i_callback(struct rcu_head *head)
kfree(dax_dev->host);
dax_dev->host = NULL;
- ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev));
+ if (inode->i_rdev)
+ ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev));
kmem_cache_free(dax_cache, dax_dev);
}
@@ -423,6 +427,7 @@ static void init_once(void *_dax_dev)
struct dax_device *dax_dev = _dax_dev;
struct inode *inode = &dax_dev->inode;
+ memset(dax_dev, 0, sizeof(*dax_dev));
inode_init_once(inode);
}