All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] Low water mark disk events
@ 2016-03-09 13:16 Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 1/4] scsi,block: enable disk event forwarding Hannes Reinecke
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Hannes Reinecke @ 2016-03-09 13:16 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Martin K. Petersen, Jeff Mahoney, linux-block,
	linux-scsi, linux-fsdevel, Hannes Reinecke

Hi all,

here is a patchset to implement 'low water mark' disk events.
This event corresponds to a TP Soft Threshold Reached UA for
SCSI or a 'low watermark' event for dm-thin.
It utilises the existing 'disk event' infrastructure from the
blocklayer to send out the events via udev.
And it also cleans up the ambiguous MEDIA_CHANGE event handling
from libata, where AN (asynchronous notification) events would
be signalled via SCSI events, and polled MEDIA_CHANGE events
would be signalled via disk events.
And I've added thin provisioning support to brd, too, to have
a simple testbed for the new low water mark disk event.

As usual, comments and reviews are welcome.

Hannes Reinecke (4):
  scsi,block: enable disk event forwarding
  block,scsi: Low water mark disk event
  dm-thin: enable low water mark disk event
  brd: thin provisioning support

 block/genhd.c              |  3 +++
 drivers/block/brd.c        | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/md/dm-thin.c       |  2 ++
 drivers/md/dm.c            | 26 +++++++++++++++++++++++
 drivers/md/dm.h            |  3 ++-
 drivers/scsi/scsi_lib.c    | 25 +++++++++-------------
 drivers/scsi/sd.c          | 44 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/sd.h          |  1 +
 include/linux/genhd.h      |  1 +
 include/scsi/scsi_driver.h |  2 ++
 10 files changed, 144 insertions(+), 16 deletions(-)

-- 
1.8.5.6


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] scsi,block: enable disk event forwarding
  2016-03-09 13:16 [RFC PATCH 0/4] Low water mark disk events Hannes Reinecke
@ 2016-03-09 13:16 ` Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 2/4] block,scsi: Low water mark disk event Hannes Reinecke
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2016-03-09 13:16 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Martin K. Petersen, Jeff Mahoney, linux-block,
	linux-scsi, linux-fsdevel, Hannes Reinecke, Hannes Reinecke

Some SCSI events relate to block events (eg media change), so this
patch implements a forwarding mechanism for SCSI events to the
corresponding block event.
It redefines the currently unused 'supported_events' bitmap to
signal which SCSI events should be forwarded to block events.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 block/genhd.c              |  1 +
 drivers/scsi/scsi_lib.c    | 15 +++++----------
 drivers/scsi/sd.c          | 26 ++++++++++++++++++++++++++
 include/scsi/scsi_driver.h |  2 ++
 4 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 9f42526..229c760 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1636,6 +1636,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
 
 	return pending;
 }
+EXPORT_SYMBOL_GPL(disk_clear_events);
 
 /*
  * Separate this part out so that a different pointer for clearing_ptr can be
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d46193a..6532c32 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2691,9 +2691,14 @@ EXPORT_SYMBOL(scsi_device_set_state);
  */
 static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
 {
+	struct device *dev = &sdev->sdev_gendev;
+	struct scsi_driver *sdrv = to_scsi_driver(dev->driver);
 	int idx = 0;
 	char *envp[3];
 
+	if (sdrv->ua_event && test_bit(evt->evt_type, sdev->supported_events))
+		sdrv->ua_event(sdev, evt->evt_type);
+
 	switch (evt->evt_type) {
 	case SDEV_EVT_MEDIA_CHANGE:
 		envp[idx++] = "SDEV_MEDIA_CHANGE=1";
@@ -2778,16 +2783,6 @@ void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt)
 {
 	unsigned long flags;
 
-#if 0
-	/* FIXME: currently this check eliminates all media change events
-	 * for polled devices.  Need to update to discriminate between AN
-	 * and polled events */
-	if (!test_bit(evt->evt_type, sdev->supported_events)) {
-		kfree(evt);
-		return;
-	}
-#endif
-
 	spin_lock_irqsave(&sdev->list_lock, flags);
 	list_add_tail(&evt->node, &sdev->event_list);
 	schedule_work(&sdev->event_work);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d749da7..b001c139 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -114,6 +114,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt);
 static void sd_uninit_command(struct scsi_cmnd *SCpnt);
 static int sd_done(struct scsi_cmnd *);
 static int sd_eh_action(struct scsi_cmnd *, int);
+static void sd_ua_event(struct scsi_device *, enum scsi_device_event);
 static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
 static void scsi_disk_release(struct device *cdev);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
@@ -525,6 +526,7 @@ static struct scsi_driver sd_template = {
 	.uninit_command		= sd_uninit_command,
 	.done			= sd_done,
 	.eh_action		= sd_eh_action,
+	.ua_event		= sd_ua_event,
 };
 
 /*
@@ -1415,6 +1417,14 @@ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
 		goto out;
 	}
 
+	if (sdp->changed) {
+		/*
+		 * Media change AN
+		 */
+		sdp->changed = 0;
+		return DISK_EVENT_MEDIA_CHANGE;
+	}
+
 	/*
 	 * Using TEST_UNIT_READY enables differentiation between drive with
 	 * no cartridge loaded - NOT READY, drive with changed cartridge -
@@ -1706,6 +1716,22 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp)
 	return eh_disp;
 }
 
+/**
+ *	sd_ua_event - unit attention event callback
+ *	@scmd:		sd-issued command which triggered the UA
+ *	@evt_type:	Triggered event type
+ *
+ **/
+static void sd_ua_event(struct scsi_device *sdev, enum scsi_device_event evt)
+{
+	struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
+
+	if (evt == SDEV_EVT_MEDIA_CHANGE) {
+		sdev->changed = 1;
+		disk_clear_events(sdkp->disk, DISK_EVENT_MEDIA_CHANGE);
+	}
+}
+
 static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
 {
 	u64 start_lba = blk_rq_pos(scmd->request);
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 891a658..1d1002a 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -7,6 +7,7 @@ struct module;
 struct request;
 struct scsi_cmnd;
 struct scsi_device;
+enum scsi_device_event;
 
 struct scsi_driver {
 	struct device_driver	gendrv;
@@ -16,6 +17,7 @@ struct scsi_driver {
 	void (*uninit_command)(struct scsi_cmnd *);
 	int (*done)(struct scsi_cmnd *);
 	int (*eh_action)(struct scsi_cmnd *, int);
+	void (*ua_event)(struct scsi_device *, enum scsi_device_event evt);
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] block,scsi: Low water mark disk event
  2016-03-09 13:16 [RFC PATCH 0/4] Low water mark disk events Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 1/4] scsi,block: enable disk event forwarding Hannes Reinecke
@ 2016-03-09 13:16 ` Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 3/4] dm-thin: enable low " Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 4/4] brd: thin provisioning support Hannes Reinecke
  3 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2016-03-09 13:16 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Martin K. Petersen, Jeff Mahoney, linux-block,
	linux-scsi, linux-fsdevel, Hannes Reinecke, Hannes Reinecke

Add a disk event for a 'low water mark' condition, signalling when
a device is about to run out of space. This event is mapped to a
Thin Provisioning Soft Threshold Reached UA.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 block/genhd.c           |  2 ++
 drivers/scsi/scsi_lib.c | 10 +++++-----
 drivers/scsi/sd.c       | 19 +++++++++++++++++++
 drivers/scsi/sd.h       |  1 +
 include/linux/genhd.h   |  1 +
 5 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 229c760..48334e6 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1437,11 +1437,13 @@ struct disk_events {
 static const char *disk_events_strs[] = {
 	[ilog2(DISK_EVENT_MEDIA_CHANGE)]	= "media_change",
 	[ilog2(DISK_EVENT_EJECT_REQUEST)]	= "eject_request",
+	[ilog2(DISK_EVENT_LOWAT)]		= "low_water_mark",
 };
 
 static char *disk_uevents[] = {
 	[ilog2(DISK_EVENT_MEDIA_CHANGE)]	= "DISK_MEDIA_CHANGE=1",
 	[ilog2(DISK_EVENT_EJECT_REQUEST)]	= "DISK_EJECT_REQUEST=1",
+	[ilog2(DISK_EVENT_LOWAT)]		= "DISK_LOW_WATER_MARK=1",
 };
 
 /* list of all disk_events */
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 6532c32..e8955da 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2683,7 +2683,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 EXPORT_SYMBOL(scsi_device_set_state);
 
 /**
- * 	sdev_evt_emit - emit a single SCSI device uevent
+ *	sdev_evt_emit - emit a single SCSI device uevent
  *	@sdev: associated SCSI device
  *	@evt: event to emit
  *
@@ -2711,7 +2711,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
 		envp[idx++] = "SDEV_UA=CAPACITY_DATA_HAS_CHANGED";
 		break;
 	case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED:
-	       envp[idx++] = "SDEV_UA=THIN_PROVISIONING_SOFT_THRESHOLD_REACHED";
+		envp[idx++] = "SDEV_UA=THIN_PROVISIONING_SOFT_THRESHOLD_REACHED";
 		break;
 	case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED:
 		envp[idx++] = "SDEV_UA=MODE_PARAMETERS_CHANGED";
@@ -2733,7 +2733,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
 }
 
 /**
- * 	sdev_evt_thread - send a uevent for each scsi event
+ *	sdev_evt_thread - send a uevent for each scsi event
  *	@work: work struct for scsi_device
  *
  *	Dispatch queued events to their associated scsi_device kobjects
@@ -2773,7 +2773,7 @@ void scsi_evt_thread(struct work_struct *work)
 }
 
 /**
- * 	sdev_evt_send - send asserted event to uevent thread
+ *	sdev_evt_send - send asserted event to uevent thread
  *	@sdev: scsi_device event occurred on
  *	@evt: event to send
  *
@@ -2791,7 +2791,7 @@ void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt)
 EXPORT_SYMBOL_GPL(sdev_evt_send);
 
 /**
- * 	sdev_evt_alloc - allocate a new scsi event
+ *	sdev_evt_alloc - allocate a new scsi event
  *	@evt_type: type of event to allocate
  *	@gfpflags: GFP flags for allocation
  *
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b001c139..34de425 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1425,6 +1425,16 @@ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
 		return DISK_EVENT_MEDIA_CHANGE;
 	}
 
+	if (sdkp->tp_lowat) {
+		/*
+		 * Thin Provisioning Low Watermark reached;
+		 * don't send TEST_UNIT_READY but rather return
+		 * immediately.
+		 */
+		sdkp->tp_lowat = false;
+		return DISK_EVENT_LOWAT;
+	}
+
 	/*
 	 * Using TEST_UNIT_READY enables differentiation between drive with
 	 * no cartridge loaded - NOT READY, drive with changed cartridge -
@@ -1729,6 +1739,9 @@ static void sd_ua_event(struct scsi_device *sdev, enum scsi_device_event evt)
 	if (evt == SDEV_EVT_MEDIA_CHANGE) {
 		sdev->changed = 1;
 		disk_clear_events(sdkp->disk, DISK_EVENT_MEDIA_CHANGE);
+	} else if (evt == SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED) {
+		sdkp->tp_lowat = true;
+		disk_clear_events(sdkp->disk, DISK_EVENT_LOWAT);
 	}
 }
 
@@ -3044,6 +3057,12 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
 		gd->flags |= GENHD_FL_REMOVABLE;
 		gd->events |= DISK_EVENT_MEDIA_CHANGE;
 	}
+	if (sdkp->lbpme) {
+		gd->events |= DISK_EVENT_LOWAT;
+		gd->async_events |= DISK_EVENT_LOWAT;
+		set_bit(SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED,
+			sdp->supported_events);
+	}
 
 	blk_pm_runtime_init(sdp->request_queue, dev);
 	add_disk(gd);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 5f2a84a..b22b8f0 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -94,6 +94,7 @@ struct scsi_disk {
 	unsigned	lbpvpd : 1;
 	unsigned	ws10 : 1;
 	unsigned	ws16 : 1;
+	unsigned	tp_lowat : 1;	/* TP soft threshold reached */
 };
 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
 
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 5c70676..d6fe7e1 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -143,6 +143,7 @@ struct hd_struct {
 enum {
 	DISK_EVENT_MEDIA_CHANGE			= 1 << 0, /* media changed */
 	DISK_EVENT_EJECT_REQUEST		= 1 << 1, /* eject requested */
+	DISK_EVENT_LOWAT			= 1 << 2, /* Low watermark reached */
 };
 
 #define BLK_SCSI_MAX_CMDS	(256)
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] dm-thin: enable low water mark disk event
  2016-03-09 13:16 [RFC PATCH 0/4] Low water mark disk events Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 1/4] scsi,block: enable disk event forwarding Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 2/4] block,scsi: Low water mark disk event Hannes Reinecke
@ 2016-03-09 13:16 ` Hannes Reinecke
  2016-03-09 13:16 ` [PATCH 4/4] brd: thin provisioning support Hannes Reinecke
  3 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2016-03-09 13:16 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Martin K. Petersen, Jeff Mahoney, linux-block,
	linux-scsi, linux-fsdevel, Hannes Reinecke, Hannes Reinecke

Enable sending of a 'low water mark' disk event and add
supporting infrastructure to the DM core.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 drivers/md/dm-thin.c |  2 ++
 drivers/md/dm.c      | 27 +++++++++++++++++++++++++++
 drivers/md/dm.h      |  3 ++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 72d91f4..c191839 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1345,6 +1345,7 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
 		spin_lock_irqsave(&pool->lock, flags);
 		pool->low_water_triggered = true;
 		spin_unlock_irqrestore(&pool->lock, flags);
+		dm_set_disk_event(pool->pool_md, DISK_EVENT_LOWAT);
 		dm_table_event(pool->ti->table);
 	}
 }
@@ -4058,6 +4059,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 		goto bad;
 	}
 	atomic_set(&tc->refcount, 1);
+	dm_enable_disk_event(pool_md, DISK_EVENT_LOWAT);
 	init_completion(&tc->can_destroy);
 	list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
 	spin_unlock_irqrestore(&tc->pool->lock, flags);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5df4048..8d22c40 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -198,6 +198,7 @@ struct mapped_device {
 	wait_queue_head_t eventq;
 	atomic_t uevent_seq;
 	struct list_head uevent_list;
+	unsigned int disk_events;
 	spinlock_t uevent_lock; /* Protect access to uevent_list */
 
 	/*
@@ -556,6 +557,16 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 	return dm_get_geometry(md, geo);
 }
 
+static unsigned int dm_check_events(struct gendisk *disk, unsigned int mask)
+{
+	struct mapped_device *md = disk->private_data;
+	unsigned int pending = md->disk_events & mask;
+
+	md->disk_events &= ~mask;
+
+	return pending;
+}
+
 static int dm_get_live_table_for_ioctl(struct mapped_device *md,
 		struct dm_target **tgt, struct block_device **bdev,
 		fmode_t *mode, int *srcu_idx)
@@ -2457,6 +2468,8 @@ static void event_callback(void *context)
 
 	dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj);
 
+	disk_clear_events(md->disk, md->disk_events);
+
 	atomic_inc(&md->event_nr);
 	wake_up(&md->eventq);
 }
@@ -3423,6 +3436,19 @@ void dm_uevent_add(struct mapped_device *md, struct list_head *elist)
 	spin_unlock_irqrestore(&md->uevent_lock, flags);
 }
 
+void dm_set_disk_event(struct mapped_device *md, unsigned int evt)
+{
+	md->disk_events |= evt;
+}
+EXPORT_SYMBOL_GPL(dm_set_disk_event);
+
+void dm_enable_disk_event(struct mapped_device *md, unsigned int evt)
+{
+	md->disk->events |= evt;
+	md->disk->async_events |= evt;
+}
+EXPORT_SYMBOL_GPL(dm_enable_disk_event);
+
 /*
  * The gendisk is only valid as long as you have a reference
  * count on 'md'.
@@ -3678,6 +3704,7 @@ static const struct block_device_operations dm_blk_dops = {
 	.ioctl = dm_blk_ioctl,
 	.getgeo = dm_blk_getgeo,
 	.pr_ops = &dm_pr_ops,
+	.check_events = dm_check_events,
 	.owner = THIS_MODULE
 };
 
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 7edcf97..fa3dc10 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -83,7 +83,8 @@ void dm_unlock_md_type(struct mapped_device *md);
 void dm_set_md_type(struct mapped_device *md, unsigned type);
 unsigned dm_get_md_type(struct mapped_device *md);
 struct target_type *dm_get_immutable_target_type(struct mapped_device *md);
-
+void dm_set_disk_event(struct mapped_device *md, unsigned int evt);
+void dm_enable_disk_event(struct mapped_device *md, unsigned int evt);
 int dm_setup_md_queue(struct mapped_device *md);
 
 /*
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] brd: thin provisioning support
  2016-03-09 13:16 [RFC PATCH 0/4] Low water mark disk events Hannes Reinecke
                   ` (2 preceding siblings ...)
  2016-03-09 13:16 ` [PATCH 3/4] dm-thin: enable low " Hannes Reinecke
@ 2016-03-09 13:16 ` Hannes Reinecke
  3 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2016-03-09 13:16 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Martin K. Petersen, Jeff Mahoney, linux-block,
	linux-scsi, linux-fsdevel, Hannes Reinecke, Hannes Reinecke

Implement module parameter 'rd_mem_size' to restrict the overall
allocated memory size and 'rd_lowat_thresh' to add a low water mark
signalling.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 drivers/block/brd.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index cb27190..a8848c3 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -30,6 +30,13 @@
 #define PAGE_SECTORS		(1 << PAGE_SECTORS_SHIFT)
 
 /*
+ * Thin provisioning support
+ */
+static unsigned int rd_total_pages;
+static int rd_mem_size = CONFIG_BLK_DEV_RAM_SIZE * CONFIG_BLK_DEV_RAM_COUNT;
+static int rd_lowat_thresh = CONFIG_BLK_DEV_RAM_SIZE * CONFIG_BLK_DEV_RAM_COUNT;
+
+/*
  * Each block ramdisk device has a radix_tree brd_pages of pages that stores
  * the pages containing the block device's contents. A brd page's ->index is
  * its offset in PAGE_SIZE units. This is similar to, but in no way connected
@@ -44,6 +51,12 @@ struct brd_device {
 	struct list_head	brd_list;
 
 	/*
+	 * Thin provisioning support
+	 */
+	unsigned int		disk_events;
+	unsigned int		pending_events;
+
+	/*
 	 * Backing store of pages and lock to protect it. This is the contents
 	 * of the block device.
 	 */
@@ -91,11 +104,23 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
 	pgoff_t idx;
 	struct page *page;
 	gfp_t gfp_flags;
+	unsigned int rd_max_pages = rd_mem_size >> (PAGE_CACHE_SHIFT - 10);
+	unsigned int rd_lowat_pages = rd_lowat_thresh >> (PAGE_CACHE_SHIFT - 10);
 
 	page = brd_lookup_page(brd, sector);
 	if (page)
 		return page;
 
+	if (rd_total_pages >= rd_max_pages)
+		return NULL;
+
+	if (rd_total_pages >= rd_lowat_pages &&
+	    !(brd->disk_events & DISK_EVENT_LOWAT)) {
+		brd->pending_events |= DISK_EVENT_LOWAT;
+		brd->disk_events |= DISK_EVENT_LOWAT;
+		disk_clear_events(brd->brd_disk, DISK_EVENT_LOWAT);
+	}
+
 	/*
 	 * Must use NOIO because we don't want to recurse back into the
 	 * block or filesystem layers from page reclaim.
@@ -127,6 +152,7 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
 		BUG_ON(!page);
 		BUG_ON(page->index != idx);
 	}
+	rd_total_pages++;
 	spin_unlock(&brd->brd_lock);
 
 	radix_tree_preload_end();
@@ -138,10 +164,16 @@ static void brd_free_page(struct brd_device *brd, sector_t sector)
 {
 	struct page *page;
 	pgoff_t idx;
+	unsigned int rd_lowat_pages = rd_lowat_thresh >> (PAGE_CACHE_SHIFT - 10);
 
 	spin_lock(&brd->brd_lock);
 	idx = sector >> PAGE_SECTORS_SHIFT;
 	page = radix_tree_delete(&brd->brd_pages, idx);
+	rd_total_pages--;
+	if (rd_total_pages < rd_lowat_pages) {
+		brd->disk_events &= ~DISK_EVENT_LOWAT;
+		brd->pending_events &= ~DISK_EVENT_LOWAT;
+	}
 	spin_unlock(&brd->brd_lock);
 	if (page)
 		__free_page(page);
@@ -434,11 +466,22 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode,
 	return error;
 }
 
+static unsigned int brd_check_events(struct gendisk *disk, unsigned int mask)
+{
+	struct brd_device *brd = disk->private_data;
+	unsigned int pending_events = brd->pending_events & mask;
+
+	brd->pending_events &= ~mask;
+
+	return pending_events;
+}
+
 static const struct block_device_operations brd_fops = {
 	.owner =		THIS_MODULE,
 	.rw_page =		brd_rw_page,
 	.ioctl =		brd_ioctl,
 	.direct_access =	brd_direct_access,
+	.check_events =		brd_check_events,
 };
 
 /*
@@ -456,6 +499,12 @@ static int max_part = 1;
 module_param(max_part, int, S_IRUGO);
 MODULE_PARM_DESC(max_part, "Num Minors to reserve between devices");
 
+module_param(rd_mem_size, int, S_IRUGO);
+MODULE_PARM_DESC(rd_mem_size, "Maximal memory size in kbytes to allocate");
+
+module_param(rd_lowat_thresh, int, S_IRUGO);
+MODULE_PARM_DESC(rd_lowat_thresh, "Low water mark in kbytes for memory allocation");
+
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
 MODULE_ALIAS("rd");
@@ -519,6 +568,8 @@ static struct brd_device *brd_alloc(int i)
 	disk->private_data	= brd;
 	disk->queue		= brd->brd_queue;
 	disk->flags		= GENHD_FL_EXT_DEVT;
+	disk->events		= DISK_EVENT_LOWAT;
+	disk->async_events	= DISK_EVENT_LOWAT;
 	sprintf(disk->disk_name, "ram%d", i);
 	set_capacity(disk, rd_size * 2);
 
@@ -607,6 +658,8 @@ static int __init brd_init(void)
 	if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
 		return -EIO;
 
+	rd_total_pages = 0;
+
 	if (unlikely(!max_part))
 		max_part = 1;
 
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-03-09 13:16 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-09 13:16 [RFC PATCH 0/4] Low water mark disk events Hannes Reinecke
2016-03-09 13:16 ` [PATCH 1/4] scsi,block: enable disk event forwarding Hannes Reinecke
2016-03-09 13:16 ` [PATCH 2/4] block,scsi: Low water mark disk event Hannes Reinecke
2016-03-09 13:16 ` [PATCH 3/4] dm-thin: enable low " Hannes Reinecke
2016-03-09 13:16 ` [PATCH 4/4] brd: thin provisioning support Hannes Reinecke

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.