[lvm-devel] [PATCH] Activate LVs read-only if underlying devices are read-only
Milan Broz
mbroz at redhat.com
Mon Feb 14 19:11:56 UTC 2011
Because of kernel changes, kernel now refuses to open device
read-write if it is internally marked read-only.
So we have to send read-only flag to kernel.
Try to check all underlying device if there are read-only
and override flag.
The same problems like scanning read-ahead here (cannot open device
while suspended so we have to cache read-only attribute).
(Patch includes mornfall's fix to postorder function.)
Signed-off-by: Milan Broz <mbroz at redhat.com>
---
lib/activate/activate.c | 3 ++
lib/activate/dev_manager.c | 12 ++++++++-
lib/device/dev-cache.c | 2 +
lib/device/dev-io.c | 36 +++++++++++++++++++++++++
lib/device/device.h | 2 +
lib/metadata/metadata.c | 62 +++++++++++++++++++++++++++++++++++--------
lib/metadata/metadata.h | 5 +++
7 files changed, 109 insertions(+), 13 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 9edb011..14b3a5e 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -1105,6 +1105,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
goto_out;
lv_calculate_readahead(lv, NULL);
+ lv_calculate_read_only(lv, NULL);
/* If VG was precommitted, preload devices for the LV */
if ((lv_pre->vg->status & PRECOMMITTED)) {
@@ -1279,6 +1280,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
goto_out;
lv_calculate_readahead(lv, NULL);
+ lv_calculate_read_only(lv, NULL);
if (!monitor_dev_for_events(cmd, lv, 0, 0))
stack;
@@ -1376,6 +1378,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
goto_out;
lv_calculate_readahead(lv, NULL);
+ lv_calculate_read_only(lv, NULL);
if (exclusive)
lv->status |= ACTIVATE_EXCL;
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index b485404..f78bd7d 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -60,7 +60,17 @@ struct lv_layer {
static int _read_only_lv(struct logical_volume *lv)
{
- return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
+ int _read_only;
+
+ _read_only = (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
+
+ if (!_read_only) {
+ lv_calculate_read_only(lv, &_read_only);
+ if (_read_only && lv_is_visible(lv))
+ log_warn("WARNING: LV %s: activating read-only.", lv->name);
+ }
+
+ return _read_only;
}
/*
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 8ba8515..10e9f5b 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -108,6 +108,7 @@ struct device *dev_create_file(const char *filename, struct device *dev,
dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT;
dev->block_size = -1;
dev->read_ahead = -1;
+ dev->read_only = -1;
memset(dev->pvid, 0, sizeof(dev->pvid));
dm_list_init(&dev->open_list);
@@ -130,6 +131,7 @@ static struct device *_dev_create(dev_t d)
dev->max_error_count = dev_disable_after_error_count();
dev->block_size = -1;
dev->read_ahead = -1;
+ dev->read_only = -1;
dev->end = UINT64_C(0);
memset(dev->pvid, 0, sizeof(dev->pvid));
dm_list_init(&dev->open_list);
diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
index eb80a89..495bd0a 100644
--- a/lib/device/dev-io.c
+++ b/lib/device/dev-io.c
@@ -301,6 +301,34 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
return 1;
}
+static int _dev_read_only_dev(struct device *dev, int *read_only)
+{
+ if (dev->read_only != -1) {
+ *read_only = dev->read_only;
+ return 1;
+ }
+
+ if (!dev_open(dev))
+ return_0;
+
+ if (ioctl(dev->fd, BLKROGET, read_only) < 0) {
+ log_sys_error("ioctl BLKROGET", dev_name(dev));
+ if (!dev_close(dev))
+ stack;
+ return 0;
+ }
+
+ if (!dev_close(dev))
+ stack;
+
+ dev->read_only = *read_only;
+
+ log_very_verbose("%s: read_only is %d",
+ dev_name(dev), *read_only);
+
+ return 1;
+}
+
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
@@ -329,6 +357,14 @@ int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead)
return _dev_read_ahead_dev(dev, read_ahead);
}
+int dev_get_read_only(struct device *dev, int *read_only)
+{
+ if (!dev)
+ return 0;
+
+ return _dev_read_only_dev(dev, read_only);
+}
+
/* FIXME Unused
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
diff --git a/lib/device/device.h b/lib/device/device.h
index 694f503..bd7dbd7 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -43,6 +43,7 @@ struct device {
int max_error_count;
int block_size;
int read_ahead;
+ int read_only;
uint32_t flags;
uint64_t end;
struct dm_list open_list;
@@ -68,6 +69,7 @@ struct device_area {
int dev_get_size(const struct device *dev, uint64_t *size);
int dev_get_sectsize(struct device *dev, uint32_t *size);
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
+int dev_get_read_only(struct device *dev, int *read_only);
/* Use quiet version if device number could change e.g. when opening LV */
int dev_open(struct device *dev);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 771cdb0..37455d1 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -1969,18 +1969,6 @@ static int _lv_postorder_visit(struct logical_volume *,
int (*fn)(struct logical_volume *lv, void *data),
void *data);
-static int _lv_postorder_level(struct logical_volume *lv, void *data)
-{
- struct _lv_postorder_baton *baton = data;
- if (lv->status & POSTORDER_OPEN_FLAG)
- return 1; // a data structure loop has closed...
- lv->status |= POSTORDER_OPEN_FLAG;
- int r =_lv_postorder_visit(lv, baton->fn, baton->data);
- lv->status &= ~POSTORDER_OPEN_FLAG;
- lv->status |= POSTORDER_FLAG;
- return r;
-};
-
static int _lv_each_dependency(struct logical_volume *lv,
int (*fn)(struct logical_volume *lv, void *data),
void *data)
@@ -2022,6 +2010,12 @@ static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
return 1;
}
+static int _lv_postorder_level(struct logical_volume *lv, void *data)
+{
+ struct _lv_postorder_baton *baton = data;
+ return _lv_postorder_visit(lv, baton->fn, baton->data);
+};
+
static int _lv_postorder_visit(struct logical_volume *lv,
int (*fn)(struct logical_volume *lv, void *data),
void *data)
@@ -2031,13 +2025,20 @@ static int _lv_postorder_visit(struct logical_volume *lv,
if (lv->status & POSTORDER_FLAG)
return 1;
+ if (lv->status & POSTORDER_OPEN_FLAG)
+ return 1; // a data structure loop has closed
+ lv->status |= POSTORDER_OPEN_FLAG;
baton.fn = fn;
baton.data = data;
r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
+
if (r)
r = fn(lv, data);
+ lv->status &= ~POSTORDER_OPEN_FLAG;
+ lv->status |= POSTORDER_FLAG;
+
return r;
}
@@ -2154,6 +2155,43 @@ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahea
}
}
+static int _lv_read_only_single(struct logical_volume *lv, void *data)
+{
+ struct lv_segment *lvseg;
+ int s, seg_read_only = 0, *read_only = data;
+
+ dm_list_iterate_items(lvseg, &lv->segments) {
+ for (s = 0; s < lvseg->area_count; ++s) {
+ if (seg_type(lvseg, s) == AREA_PV) {
+ dev_get_read_only(seg_pv(lvseg, 0)->dev, &seg_read_only);
+ if (seg_read_only)
+ goto out;
+ }
+ }
+ }
+out:
+ if (seg_read_only)
+ *read_only = 1;
+
+ return 1;
+}
+
+/*
+ * Calculate read-only for logical volume from underlying PV devices.
+ * If any of the underlying devices is read-only, set read-only to 1.
+ */
+void lv_calculate_read_only(const struct logical_volume *lv, int *read_only)
+{
+ int _read_only = 0;
+
+ _lv_postorder((struct logical_volume *)lv, _lv_read_only_single, &_read_only);
+
+ if (read_only) {
+ log_debug("Calculated read-only of LV %s is %d", lv->name, _read_only);
+ *read_only = _read_only;
+ }
+}
+
/*
* Check that an LV and all its PV references are correctly listed in vg->lvs
* and vg->pvs, respectively. This only looks at a single LV, but *not* at the
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index c0f9148..f758921 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -384,6 +384,11 @@ struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv);
void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahead);
/*
+ * Calculate read-only from underlying PV devices
+ */
+void lv_calculate_read_only(const struct logical_volume *lv, int *read_only);
+
+/*
* For internal metadata caching.
*/
int export_vg_to_buffer(struct volume_group *vg, char **buf);
--
1.7.2.3
More information about the lvm-devel
mailing list