linux-fsdevel.vger.kernel.org archive mirror
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).