* [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).