Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: John Groves <john@groves.net>
Link: https://patch.msgid.link/0100019d311d65a0-b9c1419e-f3a0-4afd-b0bd-848f18ff5950-000000@email.amazonses.com
Signed-off-by: Ira Weiny <ira.weiny@intel.com>

authored by

John Groves and committed by
Ira Weiny
700ecbc1 099c81a1

+54 -1
+16
drivers/dax/fsdev.c
··· 117 117 kill_dev_dax(dev_dax); 118 118 } 119 119 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 + 120 127 /* 121 128 * Page map operations for FS-DAX mode 122 129 * Similar to fsdax_pagemap_ops in drivers/nvdimm/pmem.c ··· 307 300 return rc; 308 301 309 302 rc = devm_add_action_or_reset(dev, fsdev_cdev_del, cdev); 303 + if (rc) 304 + return rc; 305 + 306 + /* Set the dax operations for fs-dax access path */ 307 + rc = dax_set_ops(dax_dev, &dev_dax_ops); 308 + if (rc) 309 + return rc; 310 + 311 + rc = devm_add_action_or_reset(dev, fsdev_clear_ops, dev_dax); 310 312 if (rc) 311 313 return rc; 312 314
+37 -1
drivers/dax/super.c
··· 157 157 if (!dax_alive(dax_dev)) 158 158 return -ENXIO; 159 159 160 + if (!dax_dev->ops) 161 + return -EOPNOTSUPP; 162 + 160 163 if (nr_pages < 0) 161 164 return -EINVAL; 162 165 ··· 210 207 211 208 if (!dax_alive(dax_dev)) 212 209 return -ENXIO; 210 + 211 + if (!dax_dev->ops) 212 + return -EOPNOTSUPP; 213 + 213 214 /* 214 215 * There are no callers that want to zero more than one page as of now. 215 216 * Once users are there, this check can be removed after the ··· 230 223 size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, 231 224 void *addr, size_t bytes, struct iov_iter *iter) 232 225 { 233 - if (!dax_dev->ops->recovery_write) 226 + if (!dax_dev->ops || !dax_dev->ops->recovery_write) 234 227 return 0; 235 228 return dax_dev->ops->recovery_write(dax_dev, pgoff, addr, bytes, iter); 236 229 } ··· 313 306 set_bit(DAXDEV_NOMC, &dax_dev->flags); 314 307 } 315 308 EXPORT_SYMBOL_GPL(set_dax_nomc); 309 + 310 + /** 311 + * dax_set_ops - set the dax_operations for a dax_device 312 + * @dax_dev: the dax_device to configure 313 + * @ops: the operations to set (may be NULL to clear) 314 + * 315 + * This allows drivers to set the dax_operations after the dax_device 316 + * has been allocated. This is needed when the device is created before 317 + * the driver that needs specific ops is bound (e.g., fsdev_dax binding 318 + * to a dev_dax created by hmem). 319 + * 320 + * When setting non-NULL ops, fails if ops are already set (returns -EBUSY). 321 + * When clearing ops (NULL), always succeeds. 322 + * 323 + * Return: 0 on success, -EBUSY if ops already set 324 + */ 325 + int dax_set_ops(struct dax_device *dax_dev, const struct dax_operations *ops) 326 + { 327 + if (ops) { 328 + /* Setting ops: fail if already set */ 329 + if (cmpxchg(&dax_dev->ops, NULL, ops) != NULL) 330 + return -EBUSY; 331 + } else { 332 + /* Clearing ops: always allowed */ 333 + dax_dev->ops = NULL; 334 + } 335 + return 0; 336 + } 337 + EXPORT_SYMBOL_GPL(dax_set_ops); 316 338 317 339 bool dax_alive(struct dax_device *dax_dev) 318 340 {
+1
include/linux/dax.h
··· 243 243 244 244 bool dax_alive(struct dax_device *dax_dev); 245 245 void *dax_get_private(struct dax_device *dax_dev); 246 + int dax_set_ops(struct dax_device *dax_dev, const struct dax_operations *ops); 246 247 long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, 247 248 enum dax_access_mode mode, void **kaddr, unsigned long *pfn); 248 249 size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,