@@ -3953,7 +3953,7 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 16, 0},
+ .version = {1, 17, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -4338,9 +4338,23 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
limits->max_discard_sectors = 2048 * 1024 * 16; /* 16G */
}
+static enum blk_nospace_strategy thin_get_nospace_strategy(struct dm_target *ti)
+{
+ struct thin_c *tc = ti->private;
+ struct pool *pool = tc->pool;
+
+ if (pool->pf.error_if_no_space)
+ return FAST_FAILS_IF_NOSPACE;
+
+ else if (!ACCESS_ONCE(no_space_timeout_secs))
+ return NEVER_FAILS_IF_NOSPACE;
+
+ return SLOW_FAILS_IF_NOSPACE;
+}
+
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 16, 0},
+ .version = {1, 17, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
@@ -4353,6 +4367,7 @@ static struct target_type thin_target = {
.merge = thin_merge,
.iterate_devices = thin_iterate_devices,
.io_hints = thin_io_hints,
+ .get_nospace_strategy = thin_get_nospace_strategy,
};
/*----------------------------------------------------------------*/
@@ -597,6 +597,38 @@ out:
return r;
}
+static enum blk_nospace_strategy dm_blk_get_nospace_strategy(struct block_device *bdev)
+{
+ struct mapped_device *md = bdev->bd_disk->private_data;
+ int srcu_idx;
+ struct dm_table *map;
+ struct dm_target *tgt;
+ enum blk_nospace_strategy nospace_strategy = FAST_FAILS_IF_NOSPACE;
+
+ map = dm_get_live_table(md, &srcu_idx);
+
+ if (!map || !dm_table_get_size(map))
+ goto out;
+
+ /* We only support devices that have a single target */
+ if (dm_table_get_num_targets(map) != 1)
+ goto out;
+
+ tgt = dm_table_get_target(map, 0);
+ if (!tgt->type->get_nospace_strategy)
+ goto out;
+
+ if (dm_suspended_md(md))
+ goto out;
+
+ nospace_strategy = tgt->type->get_nospace_strategy(tgt);
+
+out:
+ dm_put_live_table(md, srcu_idx);
+
+ return nospace_strategy;
+}
+
static struct dm_io *alloc_io(struct mapped_device *md)
{
return mempool_alloc(md->io_pool, GFP_NOIO);
@@ -3647,6 +3679,7 @@ static const struct block_device_operations dm_blk_dops = {
.release = dm_blk_close,
.ioctl = dm_blk_ioctl,
.getgeo = dm_blk_getgeo,
+ .get_nospace_strategy = dm_blk_get_nospace_strategy,
.owner = THIS_MODULE
};
@@ -469,6 +469,16 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector,
}
EXPORT_SYMBOL_GPL(bdev_direct_access);
+enum blk_nospace_strategy bdev_get_nospace_strategy(struct block_device *bdev)
+{
+ const struct block_device_operations *ops = bdev->bd_disk->fops;
+
+ if (!ops->get_nospace_strategy)
+ return FAST_FAILS_IF_NOSPACE;
+ return ops->get_nospace_strategy(bdev);
+}
+EXPORT_SYMBOL_GPL(bdev_get_nospace_strategy);
+
/*
* pseudo-fs
*/
@@ -1549,6 +1549,12 @@ static inline bool blk_integrity_is_initialized(struct gendisk *g)
#endif /* CONFIG_BLK_DEV_INTEGRITY */
+enum blk_nospace_strategy {
+ FAST_FAILS_IF_NOSPACE, /* immediate ENOSPC (no special handling) */
+ SLOW_FAILS_IF_NOSPACE, /* queue IO for some time, then ENOSPC */
+ NEVER_FAILS_IF_NOSPACE, /* queue IO forever */
+};
+
struct block_device_operations {
int (*open) (struct block_device *, fmode_t);
void (*release) (struct gendisk *, fmode_t);
@@ -1566,6 +1572,7 @@ struct block_device_operations {
int (*getgeo)(struct block_device *, struct hd_geometry *);
/* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
+ enum blk_nospace_strategy (*get_nospace_strategy) (struct block_device *);
struct module *owner;
};
@@ -1576,6 +1583,8 @@ extern int bdev_write_page(struct block_device *, sector_t, struct page *,
struct writeback_control *);
extern long bdev_direct_access(struct block_device *, sector_t, void **addr,
unsigned long *pfn, long size);
+extern enum blk_nospace_strategy bdev_get_nospace_strategy(struct block_device *);
+
#else /* CONFIG_BLOCK */
struct block_device;
@@ -119,6 +119,11 @@ typedef void (*dm_io_hints_fn) (struct dm_target *ti,
*/
typedef int (*dm_busy_fn) (struct dm_target *ti);
+/*
+ * Returns how the target handles -ENOSPC from lower layers.
+ */
+typedef enum blk_nospace_strategy (*dm_get_nospace_strategy_fn) (struct dm_target *ti);
+
void dm_error(const char *message);
struct dm_dev {
@@ -164,6 +169,7 @@ struct target_type {
dm_busy_fn busy;
dm_iterate_devices_fn iterate_devices;
dm_io_hints_fn io_hints;
+ dm_get_nospace_strategy_fn get_nospace_strategy;
/* For internal device-mapper use. */
struct list_head list;