Skip to content

Commit 700ecbc

Browse files
jagalacticweiny2
authored andcommitted
dax: Add dax_set_ops() for setting dax_operations at bind time
Add a new dax_set_ops() function that allows drivers to set the dax_operations after the dax_device has been allocated. This is needed for fsdev_dax where the operations need to be set during probe and cleared during unbind. The fsdev driver uses devm_add_action_or_reset() for cleanup consistency, avoiding the complexity of mixing devm-managed resources with manual cleanup in a remove() callback. This ensures cleanup happens automatically in the correct reverse order when the device is unbound. Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: John Groves <[email protected]> Link: https://patch.msgid.link/0100019d311d65a0-b9c1419e-f3a0-4afd-b0bd-848f18ff5950-000000@email.amazonses.com Signed-off-by: Ira Weiny <[email protected]>
1 parent 099c81a commit 700ecbc

3 files changed

Lines changed: 54 additions & 1 deletion

File tree

drivers/dax/fsdev.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ static void fsdev_kill(void *dev_dax)
117117
kill_dev_dax(dev_dax);
118118
}
119119

120+
static void fsdev_clear_ops(void *data)
121+
{
122+
struct dev_dax *dev_dax = data;
123+
124+
dax_set_ops(dev_dax->dax_dev, NULL);
125+
}
126+
120127
/*
121128
* Page map operations for FS-DAX mode
122129
* Similar to fsdax_pagemap_ops in drivers/nvdimm/pmem.c
@@ -303,6 +310,15 @@ static int fsdev_dax_probe(struct dev_dax *dev_dax)
303310
if (rc)
304311
return rc;
305312

313+
/* Set the dax operations for fs-dax access path */
314+
rc = dax_set_ops(dax_dev, &dev_dax_ops);
315+
if (rc)
316+
return rc;
317+
318+
rc = devm_add_action_or_reset(dev, fsdev_clear_ops, dev_dax);
319+
if (rc)
320+
return rc;
321+
306322
run_dax(dax_dev);
307323
return devm_add_action_or_reset(dev, fsdev_kill, dev_dax);
308324
}

drivers/dax/super.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
157157
if (!dax_alive(dax_dev))
158158
return -ENXIO;
159159

160+
if (!dax_dev->ops)
161+
return -EOPNOTSUPP;
162+
160163
if (nr_pages < 0)
161164
return -EINVAL;
162165

@@ -207,6 +210,10 @@ int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
207210

208211
if (!dax_alive(dax_dev))
209212
return -ENXIO;
213+
214+
if (!dax_dev->ops)
215+
return -EOPNOTSUPP;
216+
210217
/*
211218
* There are no callers that want to zero more than one page as of now.
212219
* Once users are there, this check can be removed after the
@@ -223,7 +230,7 @@ EXPORT_SYMBOL_GPL(dax_zero_page_range);
223230
size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
224231
void *addr, size_t bytes, struct iov_iter *iter)
225232
{
226-
if (!dax_dev->ops->recovery_write)
233+
if (!dax_dev->ops || !dax_dev->ops->recovery_write)
227234
return 0;
228235
return dax_dev->ops->recovery_write(dax_dev, pgoff, addr, bytes, iter);
229236
}
@@ -307,6 +314,35 @@ void set_dax_nomc(struct dax_device *dax_dev)
307314
}
308315
EXPORT_SYMBOL_GPL(set_dax_nomc);
309316

317+
/**
318+
* dax_set_ops - set the dax_operations for a dax_device
319+
* @dax_dev: the dax_device to configure
320+
* @ops: the operations to set (may be NULL to clear)
321+
*
322+
* This allows drivers to set the dax_operations after the dax_device
323+
* has been allocated. This is needed when the device is created before
324+
* the driver that needs specific ops is bound (e.g., fsdev_dax binding
325+
* to a dev_dax created by hmem).
326+
*
327+
* When setting non-NULL ops, fails if ops are already set (returns -EBUSY).
328+
* When clearing ops (NULL), always succeeds.
329+
*
330+
* Return: 0 on success, -EBUSY if ops already set
331+
*/
332+
int dax_set_ops(struct dax_device *dax_dev, const struct dax_operations *ops)
333+
{
334+
if (ops) {
335+
/* Setting ops: fail if already set */
336+
if (cmpxchg(&dax_dev->ops, NULL, ops) != NULL)
337+
return -EBUSY;
338+
} else {
339+
/* Clearing ops: always allowed */
340+
dax_dev->ops = NULL;
341+
}
342+
return 0;
343+
}
344+
EXPORT_SYMBOL_GPL(dax_set_ops);
345+
310346
bool dax_alive(struct dax_device *dax_dev)
311347
{
312348
lockdep_assert_held(&dax_srcu);

include/linux/dax.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ static inline void dax_break_layout_final(struct inode *inode)
243243

244244
bool dax_alive(struct dax_device *dax_dev);
245245
void *dax_get_private(struct dax_device *dax_dev);
246+
int dax_set_ops(struct dax_device *dax_dev, const struct dax_operations *ops);
246247
long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
247248
enum dax_access_mode mode, void **kaddr, unsigned long *pfn);
248249
size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,

0 commit comments

Comments
 (0)