# 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
}
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;
#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
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));
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);
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;
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
}
}
+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;
}
/*
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)
/* private */
int fd;
int open_count;
+ int error_count;
+ int max_error_count;
int block_size;
int read_ahead;
uint32_t flags;
else
lvmcache_lock_vgname(resource, (flags & LCK_TYPE_MASK)
== LCK_READ);
+ dev_reset_error_count(cmd);
}
_update_vg_lock_count(resource, flags);
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)
{
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));
{
return _sysfs_dir_path;
}
+
+int dev_disable_after_error_count(void)
+{
+ return _dev_disable_after_error_count;
+}
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);
#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
\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