]> sourceware.org Git - lvm2.git/commitdiff
Limit repeated accesses to broken devices.
authorPetr Rockai <prockai@redhat.com>
Wed, 13 Oct 2010 15:40:38 +0000 (15:40 +0000)
committerPetr Rockai <prockai@redhat.com>
Wed, 13 Oct 2010 15:40:38 +0000 (15:40 +0000)
Signed-off-by: Takahiro Yasui <takahiro.yasui@hds.com>
Reviewed-by: Petr Rockai <prockai@redhat.com>
doc/example.conf.in
lib/commands/toolcontext.c
lib/config/defaults.h
lib/device/dev-cache.c
lib/device/dev-cache.h
lib/device/dev-io.c
lib/device/device.h
lib/locking/locking.c
lib/misc/lvm-globals.c
lib/misc/lvm-globals.h
man/lvm.conf.5.in

index 17fca05208e3c5d8ce57bd9f35b31b5b27e1582b..6bd21ed293eafcd93319c8b237ee70d41261a23f 100644 (file)
@@ -136,6 +136,11 @@ devices {
     # in recovery situations.
     ignore_suspended_devices = 0
 
+    # During each LVM operation any errors received from a device are counted.
+    # If this counter exceeds the number here, no further I/O is sent to the
+    # device.
+    disable_after_error_count = 0
+
     # Allow use of pvcreate --uuid without requiring --restorefile.
     require_restorefile_with_uuid = 1
 }
index 289a0fcab0c36e4f13f5bbb7c557cec8dd99c0a8..a9f5bd68158eba4876f0be6388cd8f0078bf1812 100644 (file)
@@ -560,6 +560,10 @@ static int _init_dev_cache(struct cmd_context *cmd)
        const struct config_node *cn;
        struct config_value *cv;
 
+       init_dev_disable_after_error_count(
+               find_config_tree_int(cmd, "devices/disable_after_error_count",
+                                    DEFAULT_DISABLE_AFTER_ERROR_COUNT));
+
        if (!dev_cache_init(cmd))
                return_0;
 
index e4db65e9ddacbedbe9c794e1056385c2f66255e4..cbb30fa435b520bdc7d8c618f93c8caa6ba9e408 100644 (file)
@@ -33,6 +33,7 @@
 #define DEFAULT_MD_COMPONENT_DETECTION 1
 #define DEFAULT_MD_CHUNK_ALIGNMENT 1
 #define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
+#define DEFAULT_DISABLE_AFTER_ERROR_COUNT 0
 #define DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID 1
 #define DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION 1
 #define DEFAULT_DATA_ALIGNMENT_DETECTION 1
 #  define DEFAULT_MAX_HISTORY 100
 #endif
 
+#define DEFAULT_MAX_ERROR_COUNT        NO_DEV_ERROR_COUNT_LIMIT
+
 #define DEFAULT_REP_ALIGNED 1
 #define DEFAULT_REP_BUFFERED 1
 #define DEFAULT_REP_COLUMNS_AS_ROWS 0
index d43fcc02c172d97e6d50d4b2cc4171f48765ddf1..ef93f4d6915b91856860f81743eaee278c4315ef 100644 (file)
@@ -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;
index 0ade053c5e44694646b8f3999312f740249e1ae4..c1c86d6af07dc61c94a54a16c3b64e9b2377a7ad 100644 (file)
@@ -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
index 1995bdead82b5d72bd3eabd32f8b03b38827092c..eb80a8942bb87d97cf1ef05058b129e48f4796af 100644 (file)
@@ -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)
index 5a59950864fe88d7b7b0ec82726da8729653d765..694f503f58e61d7c495d8c77341ca46f3356c79c 100644 (file)
@@ -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;
index e64d227fad71035bca4c6391cc3a5112ef7729fe..94c8e8bab49eb5e28bbcb047868f3aaf2e3748fd 100644 (file)
@@ -382,6 +382,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource,
                        else
                                lvmcache_lock_vgname(resource, (flags & LCK_TYPE_MASK)
                                                                == LCK_READ);
+                       dev_reset_error_count(cmd);
                }
 
                _update_vg_lock_count(resource, flags);
index 795dd54d48aa4f278ec105a85910dac49b0cac18..9da61fe05f0ee42e5a738756236fb75aab8d69e5 100644 (file)
@@ -41,6 +41,7 @@ static int _error_message_produced = 0;
 static unsigned _is_static = 0;
 static int _udev_checking = 1;
 static char _sysfs_dir_path[PATH_MAX] = "";
+static int _dev_disable_after_error_count = DEFAULT_DISABLE_AFTER_ERROR_COUNT;
 
 void init_verbose(int level)
 {
@@ -122,6 +123,11 @@ void init_udev_checking(int checking)
                log_debug("LVM udev checking disabled");
 }
 
+void init_dev_disable_after_error_count(int value)
+{
+       _dev_disable_after_error_count = value;
+}
+
 void set_cmd_name(const char *cmd)
 {
        strncpy(_cmd_name, cmd, sizeof(_cmd_name));
@@ -236,3 +242,8 @@ const char *sysfs_dir_path()
 {
        return _sysfs_dir_path;
 }
+
+int dev_disable_after_error_count(void)
+{
+       return _dev_disable_after_error_count;
+}
index 507393cf96f7960dd3159c0b4c14f831af7ebd99..2fabbc7c1e5e145332ab9e56c15e396fd32b4da4 100644 (file)
@@ -37,6 +37,7 @@ void init_ignore_suspended_devices(int ignore);
 void init_error_message_produced(int produced);
 void init_is_static(unsigned value);
 void init_udev_checking(int checking);
+void init_dev_disable_after_error_count(int value);
 
 void set_cmd_name(const char *cmd_name);
 void set_sysfs_dir_path(const char *path);
@@ -62,4 +63,7 @@ const char *sysfs_dir_path(void);
 #define DMEVENTD_MONITOR_IGNORE -1
 int dmeventd_monitor_mode(void);
 
+#define NO_DEV_ERROR_COUNT_LIMIT 0
+int dev_disable_after_error_count(void);
+
 #endif
index ca951b5005ba063b58ac585558f03f04b186703b..35595baeebd2da8de38a0bbf068975dcb762c3a0 100644 (file)
@@ -165,6 +165,11 @@ use \fBpvs -o +pe_start\fP .  It will be a multiple of the requested
 \fBdata_alignment\fP plus the alignment_offset from
 \fBdata_alignment_offset_detection\fP (if enabled) or the pvcreate
 commandline.
+.IP
+\fBdev_max_error_count\fP \(em Maximum number of error counts per device
+before disabling devices. This option prevents a broken device from
+being accessed repeatedly. If set to 0, no access control to devices is
+done.
 .TP
 \fBlog\fP \(em Default log settings
 .IP
This page took 0.049406 seconds and 5 git commands to generate.