This patch adds 'DAXDEV_SYNC' flag which is set for nd_region doing synchronous flush. This later is used to disable MAP_SYNC functionality for ext4 & xfs filesystem for devices don't support synchronous flush.
Unified · Split
| @@ -388,7 +388,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, · 387 unmodified lines | ||
| 388 | 388 | * No 'host' or dax_operations since there is no access to this |
| 389 | 389 | * device outside of mmap of the resulting character device. |
| 390 | 390 | */ |
| 391 | − dax_dev = alloc_dax(dev_dax, NULL, NULL); | |
| 391 | + dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC); | |
| 392 | 392 | if (!dax_dev) |
| 393 | 393 | goto err; |
| 394 | 394 | |
| @@ -195,6 +195,8 @@ enum dax_device_flags { · 194 unmodified lines | ||
| 195 | 195 | DAXDEV_ALIVE, |
| 196 | 196 | /* gate whether dax_flush() calls the low level flush routine */ |
| 197 | 197 | DAXDEV_WRITE_CACHE, |
| 198 | + /* flag to check if device supports synchronous flush */ | |
| 199 | + DAXDEV_SYNC, | |
| 198 | 200 | }; |
| 199 | 201 | |
| 200 | 202 | /** |
| @@ -372,6 +374,18 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev) · 171 unmodified lines | ||
| 372 | 374 | } |
| 373 | 375 | EXPORT_SYMBOL_GPL(dax_write_cache_enabled); |
| 374 | 376 | |
| 377 | +bool __dax_synchronous(struct dax_device *dax_dev) | |
| 378 | +{ | |
| 379 | + return test_bit(DAXDEV_SYNC, &dax_dev->flags); | |
| 380 | +} | |
| 381 | +EXPORT_SYMBOL_GPL(__dax_synchronous); | |
| 382 | + | |
| 383 | +void __set_dax_synchronous(struct dax_device *dax_dev) | |
| 384 | +{ | |
| 385 | + set_bit(DAXDEV_SYNC, &dax_dev->flags); | |
| 386 | +} | |
| 387 | +EXPORT_SYMBOL_GPL(__set_dax_synchronous); | |
| 388 | + | |
| 375 | 389 | bool dax_alive(struct dax_device *dax_dev) |
| 376 | 390 | { |
| 377 | 391 | lockdep_assert_held(&dax_srcu); |
| @@ -526,7 +540,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host) · 148 unmodified lines | ||
| 526 | 540 | } |
| 527 | 541 | |
| 528 | 542 | struct dax_device *alloc_dax(void *private, const char *__host, |
| 529 | − const struct dax_operations *ops) | |
| 543 | + const struct dax_operations *ops, unsigned long flags) | |
| 530 | 544 | { |
| 531 | 545 | struct dax_device *dax_dev; |
| 532 | 546 | const char *host; |
| @@ -549,6 +563,9 @@ struct dax_device *alloc_dax(void *private, const char *__host, · 16 unmodified lines | ||
| 549 | 563 | dax_add_host(dax_dev, host); |
| 550 | 564 | dax_dev->ops = ops; |
| 551 | 565 | dax_dev->private = private; |
| 566 | + if (flags & DAXDEV_F_SYNC) | |
| 567 | + set_dax_synchronous(dax_dev); | |
| 568 | + | |
| 552 | 569 | return dax_dev; |
| 553 | 570 | |
| 554 | 571 | err_dev: |
| @@ -1991,7 +1991,8 @@ static struct mapped_device *alloc_dev(int minor) · 1990 unmodified lines | ||
| 1991 | 1991 | sprintf(md->disk->disk_name, "dm-%d", minor); |
| 1992 | 1992 | |
| 1993 | 1993 | if (IS_ENABLED(CONFIG_DAX_DRIVER)) { |
| 1994 | − md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); | |
| 1994 | + md->dax_dev = alloc_dax(md, md->disk->disk_name, | |
| 1995 | + &dm_dax_ops, 0); | |
| 1995 | 1996 | if (!md->dax_dev) |
| 1996 | 1997 | goto bad; |
| 1997 | 1998 | } |
| @@ -376,6 +376,7 @@ static int pmem_attach_disk(struct device *dev, · 375 unmodified lines | ||
| 376 | 376 | struct gendisk *disk; |
| 377 | 377 | void *addr; |
| 378 | 378 | int rc; |
| 379 | + unsigned long flags = 0UL; | |
| 379 | 380 | |
| 380 | 381 | pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL); |
| 381 | 382 | if (!pmem) |
| @@ -474,7 +475,9 @@ static int pmem_attach_disk(struct device *dev, · 92 unmodified lines | ||
| 474 | 475 | nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res); |
| 475 | 476 | disk->bb = &pmem->bb; |
| 476 | 477 | |
| 477 | − dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops); | |
| 478 | + if (is_nvdimm_sync(nd_region)) | |
| 479 | + flags = DAXDEV_F_SYNC; | |
| 480 | + dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags); | |
| 478 | 481 | if (!dax_dev) { |
| 479 | 482 | put_disk(disk); |
| 480 | 483 | return -ENOMEM; |
| @@ -1211,6 +1211,13 @@ int nvdimm_has_cache(struct nd_region *nd_region) · 1210 unmodified lines | ||
| 1211 | 1211 | } |
| 1212 | 1212 | EXPORT_SYMBOL_GPL(nvdimm_has_cache); |
| 1213 | 1213 | |
| 1214 | +bool is_nvdimm_sync(struct nd_region *nd_region) | |
| 1215 | +{ | |
| 1216 | + return is_nd_pmem(&nd_region->dev) && | |
| 1217 | + !test_bit(ND_REGION_ASYNC, &nd_region->flags); | |
| 1218 | +} | |
| 1219 | +EXPORT_SYMBOL_GPL(is_nvdimm_sync); | |
| 1220 | + | |
| 1214 | 1221 | struct conflict_context { |
| 1215 | 1222 | struct nd_region *nd_region; |
| 1216 | 1223 | resource_size_t start, size; |
| @@ -679,7 +679,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char · 678 unmodified lines | ||
| 679 | 679 | goto put_dev; |
| 680 | 680 | |
| 681 | 681 | dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name, |
| 682 | − &dcssblk_dax_ops); | |
| 682 | + &dcssblk_dax_ops, DAXDEV_F_SYNC); | |
| 683 | 683 | if (!dev_info->dax_dev) { |
| 684 | 684 | rc = -ENOMEM; |
| 685 | 685 | goto put_dev; |
| @@ -7,6 +7,9 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/radix-tree.h> |
| 8 | 8 | #include <asm/pgtable.h> |
| 9 | 9 | |
| 10 | +/* Flag for synchronous flush */ | |
| 11 | +#define DAXDEV_F_SYNC (1UL << 0) | |
| 12 | + | |
| 10 | 13 | typedef unsigned long dax_entry_t; |
| 11 | 14 | |
| 12 | 15 | struct iomap_ops; |
| @@ -38,18 +41,28 @@ extern struct attribute_group dax_attribute_group; · 25 unmodified lines | ||
| 38 | 41 | #if IS_ENABLED(CONFIG_DAX) |
| 39 | 42 | struct dax_device *dax_get_by_host(const char *host); |
| 40 | 43 | struct dax_device *alloc_dax(void *private, const char *host, |
| 41 | − const struct dax_operations *ops); | |
| 44 | + const struct dax_operations *ops, unsigned long flags); | |
| 42 | 45 | void put_dax(struct dax_device *dax_dev); |
| 43 | 46 | void kill_dax(struct dax_device *dax_dev); |
| 44 | 47 | void dax_write_cache(struct dax_device *dax_dev, bool wc); |
| 45 | 48 | bool dax_write_cache_enabled(struct dax_device *dax_dev); |
| 49 | +bool __dax_synchronous(struct dax_device *dax_dev); | |
| 50 | +static inline bool dax_synchronous(struct dax_device *dax_dev) | |
| 51 | +{ | |
| 52 | + return __dax_synchronous(dax_dev); | |
| 53 | +} | |
| 54 | +void __set_dax_synchronous(struct dax_device *dax_dev); | |
| 55 | +static inline void set_dax_synchronous(struct dax_device *dax_dev) | |
| 56 | +{ | |
| 57 | + __set_dax_synchronous(dax_dev); | |
| 58 | +} | |
| 46 | 59 | #else |
| 47 | 60 | static inline struct dax_device *dax_get_by_host(const char *host) |
| 48 | 61 | { |
| 49 | 62 | return NULL; |
| 50 | 63 | } |
| 51 | 64 | static inline struct dax_device *alloc_dax(void *private, const char *host, |
| 52 | − const struct dax_operations *ops) | |
| 65 | + const struct dax_operations *ops, unsigned long flags) | |
| 53 | 66 | { |
| 54 | 67 | /* |
| 55 | 68 | * Callers should check IS_ENABLED(CONFIG_DAX) to know if this |
| @@ -70,6 +83,13 @@ static inline bool dax_write_cache_enabled(struct dax_device *dax_dev) · 14 unmodified lines | ||
| 70 | 83 | { |
| 71 | 84 | return false; |
| 72 | 85 | } |
| 86 | +static inline bool dax_synchronous(struct dax_device *dax_dev) | |
| 87 | +{ | |
| 88 | + return true; | |
| 89 | +} | |
| 90 | +static inline void set_dax_synchronous(struct dax_device *dax_dev) | |
| 91 | +{ | |
| 92 | +} | |
| 73 | 93 | #endif |
| 74 | 94 | |
| 75 | 95 | struct writeback_control; |
| @@ -263,6 +263,7 @@ int generic_nvdimm_flush(struct nd_region *nd_region); · 262 unmodified lines | ||
| 263 | 263 | int nvdimm_has_flush(struct nd_region *nd_region); |
| 264 | 264 | int nvdimm_has_cache(struct nd_region *nd_region); |
| 265 | 265 | int nvdimm_in_overwrite(struct nvdimm *nvdimm); |
| 266 | +bool is_nvdimm_sync(struct nd_region *nd_region); | |
| 266 | 267 | |
| 267 | 268 | static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
| 268 | 269 | unsigned int buf_len, int *cmd_rc) |