From 976b95d9290ad0e9ef10bdd35fe3ed08270666b8 Mon Sep 17 00:00:00 2001 From: Petr Rockai Date: Wed, 13 Oct 2010 15:40:38 +0000 Subject: Limit repeated accesses to broken devices. Signed-off-by: Takahiro Yasui Reviewed-by: Petr Rockai --- lib/device/dev-cache.c | 19 +++++++++++++++++++ lib/device/dev-cache.h | 2 ++ lib/device/dev-io.c | 34 ++++++++++++++++++++++++++++++++-- lib/device/device.h | 2 ++ 4 files changed, 55 insertions(+), 2 deletions(-) (limited to 'lib/device') diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index d43fcc02..ef93f4d6 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -104,6 +104,8 @@ struct device *dev_create_file(const char *filename, struct device *dev, dev->dev = 0; dev->fd = -1; dev->open_count = 0; + dev->error_count = 0; + dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT; dev->block_size = -1; dev->read_ahead = -1; memset(dev->pvid, 0, sizeof(dev->pvid)); @@ -125,6 +127,7 @@ static struct device *_dev_create(dev_t d) dev->dev = d; dev->fd = -1; dev->open_count = 0; + dev->max_error_count = dev_disable_after_error_count(); dev->block_size = -1; dev->read_ahead = -1; dev->end = UINT64_C(0); @@ -845,6 +848,22 @@ struct device *dev_iter_get(struct dev_iter *iter) return NULL; } +void dev_reset_error_count(struct cmd_context *cmd) +{ + struct dev_iter *iter; + struct device *dev; + + if (!(iter = dev_iter_create(cmd->filter, 0))) { + log_error("Resetting device error count failed"); + return; + } + + for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) + dev->error_count = 0; + + dev_iter_destroy(iter); +} + int dev_fd(struct device *dev) { return dev->fd; diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h index 0ade053c..c1c86d6a 100644 --- a/lib/device/dev-cache.h +++ b/lib/device/dev-cache.h @@ -53,4 +53,6 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan); void dev_iter_destroy(struct dev_iter *iter); struct device *dev_iter_get(struct dev_iter *iter); +void dev_reset_error_count(struct cmd_context *cmd); + #endif diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index 1995bdea..eb80a894 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -603,18 +603,40 @@ void dev_close_all(void) } } +static inline int _dev_is_valid(struct device *dev) +{ + return (dev->max_error_count == NO_DEV_ERROR_COUNT_LIMIT || + dev->error_count < dev->max_error_count); +} + +static void _dev_inc_error_count(struct device *dev) +{ + if (++dev->error_count == dev->max_error_count) + log_warn("WARNING: Error counts reached a limit of %d. " + "Device %s was disabled", + dev->max_error_count, dev_name(dev)); +} + int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) { struct device_area where; + int ret; if (!dev->open_count) return_0; + if (!_dev_is_valid(dev)) + return 0; + where.dev = dev; where.start = offset; where.size = len; - return _aligned_io(&where, buffer, 0); + ret = _aligned_io(&where, buffer, 0); + if (!ret) + _dev_inc_error_count(dev); + + return ret; } /* @@ -670,17 +692,25 @@ int dev_append(struct device *dev, size_t len, void *buffer) int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) { struct device_area where; + int ret; if (!dev->open_count) return_0; + if (!_dev_is_valid(dev)) + return 0; + where.dev = dev; where.start = offset; where.size = len; dev->flags |= DEV_ACCESSED_W; - return _aligned_io(&where, buffer, 1); + ret = _aligned_io(&where, buffer, 1); + if (!ret) + _dev_inc_error_count(dev); + + return ret; } int dev_set(struct device *dev, uint64_t offset, size_t len, int value) diff --git a/lib/device/device.h b/lib/device/device.h index 5a599508..694f503f 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -39,6 +39,8 @@ struct device { /* private */ int fd; int open_count; + int error_count; + int max_error_count; int block_size; int read_ahead; uint32_t flags; -- cgit