diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2010-09-01 08:39:30 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 12:38:28 -0400 |
commit | ef50a3e34f93a067ada541346be3175e924331a2 (patch) | |
tree | 455fd4a7d4b11ead24b7e297f25b02afabc36c76 /drivers/block | |
parent | 3f3a9b849d2b703934c07fa17f5eac2dc37c1f6b (diff) |
drbd: implicitly create unconfigured devices on sync-after dependencies
If pacemaker (for example) decided to initialize minor devices not in
the exact sync-after dependency order, the configuration partially
failed with an error "The sync-after minor number is invalid". (Bugz. #322)
We can avoid that by implicitly creating unconfigured minor devices,
if others depend on them.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 76 |
1 files changed, 41 insertions, 35 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index d066190f997a..e0061a906ba8 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -413,6 +413,39 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
413 | return r; | 413 | return r; |
414 | } | 414 | } |
415 | 415 | ||
416 | static struct drbd_conf *ensure_mdev(int minor, int create) | ||
417 | { | ||
418 | struct drbd_conf *mdev; | ||
419 | |||
420 | if (minor >= minor_count) | ||
421 | return NULL; | ||
422 | |||
423 | mdev = minor_to_mdev(minor); | ||
424 | |||
425 | if (!mdev && create) { | ||
426 | struct gendisk *disk = NULL; | ||
427 | mdev = drbd_new_device(minor); | ||
428 | |||
429 | spin_lock_irq(&drbd_pp_lock); | ||
430 | if (minor_table[minor] == NULL) { | ||
431 | minor_table[minor] = mdev; | ||
432 | disk = mdev->vdisk; | ||
433 | mdev = NULL; | ||
434 | } /* else: we lost the race */ | ||
435 | spin_unlock_irq(&drbd_pp_lock); | ||
436 | |||
437 | if (disk) /* we won the race above */ | ||
438 | /* in case we ever add a drbd_delete_device(), | ||
439 | * don't forget the del_gendisk! */ | ||
440 | add_disk(disk); | ||
441 | else /* we lost the race above */ | ||
442 | drbd_free_mdev(mdev); | ||
443 | |||
444 | mdev = minor_to_mdev(minor); | ||
445 | } | ||
446 | |||
447 | return mdev; | ||
448 | } | ||
416 | 449 | ||
417 | static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | 450 | static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, |
418 | struct drbd_nl_cfg_reply *reply) | 451 | struct drbd_nl_cfg_reply *reply) |
@@ -1713,6 +1746,12 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n | |||
1713 | } | 1746 | } |
1714 | #undef AL_MAX | 1747 | #undef AL_MAX |
1715 | 1748 | ||
1749 | /* to avoid spurious errors when configuring minors before configuring | ||
1750 | * the minors they depend on: if necessary, first create the minor we | ||
1751 | * depend on */ | ||
1752 | if (sc.after >= 0) | ||
1753 | ensure_mdev(sc.after, 1); | ||
1754 | |||
1716 | /* most sanity checks done, try to assign the new sync-after | 1755 | /* most sanity checks done, try to assign the new sync-after |
1717 | * dependency. need to hold the global lock in there, | 1756 | * dependency. need to hold the global lock in there, |
1718 | * to avoid a race in the dependency loop check. */ | 1757 | * to avoid a race in the dependency loop check. */ |
@@ -2080,40 +2119,6 @@ out: | |||
2080 | return 0; | 2119 | return 0; |
2081 | } | 2120 | } |
2082 | 2121 | ||
2083 | static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp) | ||
2084 | { | ||
2085 | struct drbd_conf *mdev; | ||
2086 | |||
2087 | if (nlp->drbd_minor >= minor_count) | ||
2088 | return NULL; | ||
2089 | |||
2090 | mdev = minor_to_mdev(nlp->drbd_minor); | ||
2091 | |||
2092 | if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) { | ||
2093 | struct gendisk *disk = NULL; | ||
2094 | mdev = drbd_new_device(nlp->drbd_minor); | ||
2095 | |||
2096 | spin_lock_irq(&drbd_pp_lock); | ||
2097 | if (minor_table[nlp->drbd_minor] == NULL) { | ||
2098 | minor_table[nlp->drbd_minor] = mdev; | ||
2099 | disk = mdev->vdisk; | ||
2100 | mdev = NULL; | ||
2101 | } /* else: we lost the race */ | ||
2102 | spin_unlock_irq(&drbd_pp_lock); | ||
2103 | |||
2104 | if (disk) /* we won the race above */ | ||
2105 | /* in case we ever add a drbd_delete_device(), | ||
2106 | * don't forget the del_gendisk! */ | ||
2107 | add_disk(disk); | ||
2108 | else /* we lost the race above */ | ||
2109 | drbd_free_mdev(mdev); | ||
2110 | |||
2111 | mdev = minor_to_mdev(nlp->drbd_minor); | ||
2112 | } | ||
2113 | |||
2114 | return mdev; | ||
2115 | } | ||
2116 | |||
2117 | struct cn_handler_struct { | 2122 | struct cn_handler_struct { |
2118 | int (*function)(struct drbd_conf *, | 2123 | int (*function)(struct drbd_conf *, |
2119 | struct drbd_nl_cfg_req *, | 2124 | struct drbd_nl_cfg_req *, |
@@ -2174,7 +2179,8 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms | |||
2174 | goto fail; | 2179 | goto fail; |
2175 | } | 2180 | } |
2176 | 2181 | ||
2177 | mdev = ensure_mdev(nlp); | 2182 | mdev = ensure_mdev(nlp->drbd_minor, |
2183 | (nlp->flags & DRBD_NL_CREATE_DEVICE)); | ||
2178 | if (!mdev) { | 2184 | if (!mdev) { |
2179 | retcode = ERR_MINOR_INVALID; | 2185 | retcode = ERR_MINOR_INVALID; |
2180 | goto fail; | 2186 | goto fail; |