[PATCH V12 01/12] dax: replace exported dax_dev_get() with non-allocating dax_dev_find()

John Groves <[email protected]> Mon, 3 Aug 2026 02:28:26 +0000
Newsgroups dev.linux.lists.nvdimm,dev.linux.lists.fuse-devel,org.kernel.vger.linux-cxl,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <0100019fc5737596-636bde4f-7fc7-46a4-b011-63870098df09-000000@email.amazonses.com>
From: John Groves <[email protected]>=0D=0A=0D=0AThis fix is in response to=
 a Sashiko review, and some subsequent=0D=0Aanalysis.=0D=0A=0D=0Adax_dev_=
get() uses iget5_locked() which creates a new inode if no=0D=0Amatching o=
ne exists. This is correct for the internal caller=0D=0A(alloc_dax), but =
dangerous for external callers that look up devices=0D=0Afrom user-suppli=
ed or metadata-supplied dev_t values:=0D=0A=0D=0A1. A new inode is create=
d with DAXDEV_ALIVE set but no backing driver,=0D=0A   no ops, and no IDA=
-allocated minor number.=0D=0A=0D=0A2. On teardown, dax_destroy_inode() w=
arns because kill_dax() was never=0D=0A   called, and dax_free_inode() ca=
lls ida_free() for a minor that was=0D=0A   never ida_alloc'd -- potentia=
lly freeing the minor of a real device.=0D=0A=0D=0AAdd dax_dev_find() whi=
ch uses ilookup5() for lookup-only semantics:=0D=0Ait returns an existing=
 dax_device with an elevated inode reference, or=0D=0ANULL if no device w=
ith the given dev_t exists. It never creates inodes.=0D=0AA dax_alive() c=
heck under dax_read_lock() guards against returning a=0D=0Adevice that is=
 concurrently being torn down by kill_dax().=0D=0A=0D=0AMake dax_dev_get(=
) static again (internal to super.c for alloc_dax),=0D=0Aexport dax_dev_f=
ind() instead, and update the two external callers=0D=0A(famfs_inode.c, f=
amfs.c). Also add the missing CONFIG_DAX=3Dn stub.=0D=0A=0D=0AAbout the '=
fixes' tag: this removes the export of dax_dev_get(),=0D=0Awhich was flaw=
ed, and replaces is with dax_dev_find(). It feels like=0D=0Athe fixes tag=
 makes sense for correcting an ABI error.=0D=0A=0D=0AFixes: 2ae624d5a555d=
 ("dax: export dax_dev_get()")=0D=0A=0D=0AReviewed-by: Dave Jiang <dave.j=
[email protected]>=0D=0AReviewed-by: Alison Schofield <alison.schofield@inte=
l.com>=0D=0ASigned-off-by: John Groves <[email protected]>=0D=0A---=0D=0A d=
rivers/dax/super.c | 38 ++++++++++++++++++++++++++++++++++++--=0D=0A incl=
ude/linux/dax.h |  6 +++++-=0D=0A 2 files changed, 41 insertions(+), 3 de=
letions(-)=0D=0A=0D=0Adiff --git a/drivers/dax/super.c b/drivers/dax/supe=
r.c=0D=0Aindex 25cf99dd9360..0fc14d4f8198 100644=0D=0A--- a/drivers/dax/s=
uper.c=0D=0A+++ b/drivers/dax/super.c=0D=0A@@ -521,7 +521,7 @@ static int=
 dax_set(struct inode *inode, void *data)=0D=0A =09return 0;=0D=0A }=0D=0A=
=20=0D=0A-struct dax_device *dax_dev_get(dev_t devt)=0D=0A+static struct =
dax_device *dax_dev_get(dev_t devt)=0D=0A {=0D=0A =09struct dax_device *d=
ax_dev;=0D=0A =09struct inode *inode;=0D=0A@@ -544,7 +544,41 @@ struct da=
x_device *dax_dev_get(dev_t devt)=0D=0A=20=0D=0A =09return dax_dev;=0D=0A=
 }=0D=0A-EXPORT_SYMBOL_GPL(dax_dev_get);=0D=0A+=0D=0A+/**=0D=0A+ * dax_de=
v_find - look up an existing dax_device by dev_t=0D=0A+ * @devt: the devi=
ce number to find=0D=0A+ *=0D=0A+ * Returns a dax_device with an elevated=
 inode reference, or NULL if no=0D=0A+ * device with the given dev_t exis=
ts. Unlike dax_dev_get(), this never=0D=0A+ * allocates a new inode -- it=
 is safe for external callers that are looking=0D=0A+ * up devices from u=
ser-supplied or metadata-supplied dev_t values.=0D=0A+ *=0D=0A+ * Caller =
must put_dax() the returned device when done.=0D=0A+ */=0D=0A+struct dax_=
device *dax_dev_find(dev_t devt)=0D=0A+{=0D=0A+=09struct dax_device *dax_=
dev;=0D=0A+=09struct inode *inode;=0D=0A+=09int id;=0D=0A+=0D=0A+=09inode=
 =3D ilookup5(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31),=0D=0A+=09=09=
=09 dax_test, &devt);=0D=0A+=09if (!inode)=0D=0A+=09=09return NULL;=0D=0A=
+=0D=0A+=09dax_dev =3D to_dax_dev(inode);=0D=0A+=09id =3D dax_read_lock()=
;=0D=0A+=09if (!dax_alive(dax_dev)) {=0D=0A+=09=09dax_read_unlock(id);=0D=
=0A+=09=09iput(inode);=0D=0A+=09=09return NULL;=0D=0A+=09}=0D=0A+=09dax_r=
ead_unlock(id);=0D=0A+=0D=0A+=09return dax_dev;=0D=0A+}=0D=0A+EXPORT_SYMB=
OL_GPL(dax_dev_find);=0D=0A=20=0D=0A struct dax_device *alloc_dax(void *p=
rivate, const struct dax_operations *ops)=0D=0A {=0D=0Adiff --git a/inclu=
de/linux/dax.h b/include/linux/dax.h=0D=0Aindex fe6c3ded1b50..29113eb95e7=
2 100644=0D=0A--- a/include/linux/dax.h=0D=0A+++ b/include/linux/dax.h=0D=
=0A@@ -54,7 +54,7 @@ struct dax_device *alloc_dax(void *private, const st=
ruct dax_operations *ops);=0D=0A void *dax_holder(struct dax_device *dax_=
dev);=0D=0A void put_dax(struct dax_device *dax_dev);=0D=0A void kill_dax=
(struct dax_device *dax_dev);=0D=0A-struct dax_device *dax_dev_get(dev_t =
devt);=0D=0A+struct dax_device *dax_dev_find(dev_t devt);=0D=0A void dax_=
write_cache(struct dax_device *dax_dev, bool wc);=0D=0A bool dax_write_ca=
che_enabled(struct dax_device *dax_dev);=0D=0A bool dax_synchronous(struc=
t dax_device *dax_dev);=0D=0A@@ -92,6 +92,10 @@ static inline void put_da=
x(struct dax_device *dax_dev)=0D=0A static inline void kill_dax(struct da=
x_device *dax_dev)=0D=0A {=0D=0A }=0D=0A+static inline struct dax_device =
*dax_dev_find(dev_t devt)=0D=0A+{=0D=0A+=09return NULL;=0D=0A+}=0D=0A sta=
tic inline void dax_write_cache(struct dax_device *dax_dev, bool wc)=0D=0A=
 {=0D=0A }=0D=0A--=20=0D=0A2.53.0=0D=0A=0D=0A