[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.fuse-devel,dev.linux.lists.nvdimm,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