diff options
| author | Yehuda Sadeh <yehuda@hq.newdream.net> | 2011-03-21 18:10:11 -0400 |
|---|---|---|
| committer | Sage Weil <sage@newdream.net> | 2011-03-22 14:33:56 -0400 |
| commit | 59c2be1e4d42c0d4949cecdeef3f37070a1fbc13 (patch) | |
| tree | 919f191a2f2840b510dce246210564bf45200616 | |
| parent | a40c4f10e3fb96030358e49abd010c1f08446fa3 (diff) | |
rbd: use watch/notify for changes in rbd header
Send notifications when we change the rbd header (e.g. create a snapshot)
and wait for such notifications. This allows synchronizing the snapshot
creation between different rbd clients/rools.
Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
| -rw-r--r-- | drivers/block/rbd.c | 361 |
1 files changed, 335 insertions, 26 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index e1e38b11f48a..16dc3645291c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/ceph/osd_client.h> | 31 | #include <linux/ceph/osd_client.h> |
| 32 | #include <linux/ceph/mon_client.h> | 32 | #include <linux/ceph/mon_client.h> |
| 33 | #include <linux/ceph/decode.h> | 33 | #include <linux/ceph/decode.h> |
| 34 | #include <linux/parser.h> | ||
| 34 | 35 | ||
| 35 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
| 36 | #include <linux/device.h> | 37 | #include <linux/device.h> |
| @@ -54,6 +55,8 @@ | |||
| 54 | 55 | ||
| 55 | #define DEV_NAME_LEN 32 | 56 | #define DEV_NAME_LEN 32 |
| 56 | 57 | ||
| 58 | #define RBD_NOTIFY_TIMEOUT_DEFAULT 10 | ||
| 59 | |||
| 57 | /* | 60 | /* |
| 58 | * block device image metadata (in-memory version) | 61 | * block device image metadata (in-memory version) |
| 59 | */ | 62 | */ |
| @@ -71,6 +74,12 @@ struct rbd_image_header { | |||
| 71 | 74 | ||
| 72 | char *snap_names; | 75 | char *snap_names; |
| 73 | u64 *snap_sizes; | 76 | u64 *snap_sizes; |
| 77 | |||
| 78 | u64 obj_version; | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct rbd_options { | ||
| 82 | int notify_timeout; | ||
| 74 | }; | 83 | }; |
| 75 | 84 | ||
| 76 | /* | 85 | /* |
| @@ -78,6 +87,7 @@ struct rbd_image_header { | |||
| 78 | */ | 87 | */ |
| 79 | struct rbd_client { | 88 | struct rbd_client { |
| 80 | struct ceph_client *client; | 89 | struct ceph_client *client; |
| 90 | struct rbd_options *rbd_opts; | ||
| 81 | struct kref kref; | 91 | struct kref kref; |
| 82 | struct list_head node; | 92 | struct list_head node; |
| 83 | }; | 93 | }; |
| @@ -124,6 +134,9 @@ struct rbd_device { | |||
| 124 | char pool_name[RBD_MAX_POOL_NAME_LEN]; | 134 | char pool_name[RBD_MAX_POOL_NAME_LEN]; |
| 125 | int poolid; | 135 | int poolid; |
| 126 | 136 | ||
| 137 | struct ceph_osd_event *watch_event; | ||
| 138 | struct ceph_osd_request *watch_request; | ||
| 139 | |||
| 127 | char snap_name[RBD_MAX_SNAP_NAME_LEN]; | 140 | char snap_name[RBD_MAX_SNAP_NAME_LEN]; |
| 128 | u32 cur_snap; /* index+1 of current snapshot within snap context | 141 | u32 cur_snap; /* index+1 of current snapshot within snap context |
| 129 | 0 - for the head */ | 142 | 0 - for the head */ |
| @@ -177,6 +190,8 @@ static void rbd_put_dev(struct rbd_device *rbd_dev) | |||
| 177 | put_device(&rbd_dev->dev); | 190 | put_device(&rbd_dev->dev); |
| 178 | } | 191 | } |
| 179 | 192 | ||
| 193 | static int __rbd_update_snaps(struct rbd_device *rbd_dev); | ||
| 194 | |||
| 180 | static int rbd_open(struct block_device *bdev, fmode_t mode) | 195 | static int rbd_open(struct block_device *bdev, fmode_t mode) |
| 181 | { | 196 | { |
| 182 | struct gendisk *disk = bdev->bd_disk; | 197 | struct gendisk *disk = bdev->bd_disk; |
| @@ -211,7 +226,8 @@ static const struct block_device_operations rbd_bd_ops = { | |||
| 211 | * Initialize an rbd client instance. | 226 | * Initialize an rbd client instance. |
| 212 | * We own *opt. | 227 | * We own *opt. |
| 213 | */ | 228 | */ |
| 214 | static struct rbd_client *rbd_client_create(struct ceph_options *opt) | 229 | static struct rbd_client *rbd_client_create(struct ceph_options *opt, |
| 230 | struct rbd_options *rbd_opts) | ||
| 215 | { | 231 | { |
| 216 | struct rbd_client *rbdc; | 232 | struct rbd_client *rbdc; |
| 217 | int ret = -ENOMEM; | 233 | int ret = -ENOMEM; |
| @@ -233,6 +249,8 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt) | |||
| 233 | if (ret < 0) | 249 | if (ret < 0) |
| 234 | goto out_err; | 250 | goto out_err; |
| 235 | 251 | ||
| 252 | rbdc->rbd_opts = rbd_opts; | ||
| 253 | |||
| 236 | spin_lock(&node_lock); | 254 | spin_lock(&node_lock); |
| 237 | list_add_tail(&rbdc->node, &rbd_client_list); | 255 | list_add_tail(&rbdc->node, &rbd_client_list); |
| 238 | spin_unlock(&node_lock); | 256 | spin_unlock(&node_lock); |
| @@ -267,6 +285,59 @@ static struct rbd_client *__rbd_client_find(struct ceph_options *opt) | |||
| 267 | } | 285 | } |
| 268 | 286 | ||
| 269 | /* | 287 | /* |
| 288 | * mount options | ||
| 289 | */ | ||
| 290 | enum { | ||
| 291 | Opt_notify_timeout, | ||
| 292 | Opt_last_int, | ||
| 293 | /* int args above */ | ||
| 294 | Opt_last_string, | ||
| 295 | /* string args above */ | ||
| 296 | }; | ||
| 297 | |||
| 298 | static match_table_t rbdopt_tokens = { | ||
| 299 | {Opt_notify_timeout, "notify_timeout=%d"}, | ||
| 300 | /* int args above */ | ||
| 301 | /* string args above */ | ||
| 302 | {-1, NULL} | ||
| 303 | }; | ||
| 304 | |||
| 305 | static int parse_rbd_opts_token(char *c, void *private) | ||
| 306 | { | ||
| 307 | struct rbd_options *rbdopt = private; | ||
| 308 | substring_t argstr[MAX_OPT_ARGS]; | ||
| 309 | int token, intval, ret; | ||
| 310 | |||
| 311 | token = match_token((char *)c, rbdopt_tokens, argstr); | ||
| 312 | if (token < 0) | ||
| 313 | return -EINVAL; | ||
| 314 | |||
| 315 | if (token < Opt_last_int) { | ||
| 316 | ret = match_int(&argstr[0], &intval); | ||
| 317 | if (ret < 0) { | ||
| 318 | pr_err("bad mount option arg (not int) " | ||
| 319 | "at '%s'\n", c); | ||
| 320 | return ret; | ||
| 321 | } | ||
| 322 | dout("got int token %d val %d\n", token, intval); | ||
| 323 | } else if (token > Opt_last_int && token < Opt_last_string) { | ||
| 324 | dout("got string token %d val %s\n", token, | ||
| 325 | argstr[0].from); | ||
| 326 | } else { | ||
| 327 | dout("got token %d\n", token); | ||
| 328 | } | ||
| 329 | |||
| 330 | switch (token) { | ||
| 331 | case Opt_notify_timeout: | ||
| 332 | rbdopt->notify_timeout = intval; | ||
| 333 | break; | ||
| 334 | default: | ||
| 335 | BUG_ON(token); | ||
| 336 | } | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* | ||
| 270 | * Get a ceph client with specific addr and configuration, if one does | 341 | * Get a ceph client with specific addr and configuration, if one does |
| 271 | * not exist create it. | 342 | * not exist create it. |
| 272 | */ | 343 | */ |
| @@ -276,11 +347,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, | |||
| 276 | struct rbd_client *rbdc; | 347 | struct rbd_client *rbdc; |
| 277 | struct ceph_options *opt; | 348 | struct ceph_options *opt; |
| 278 | int ret; | 349 | int ret; |
| 350 | struct rbd_options *rbd_opts; | ||
| 351 | |||
| 352 | rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL); | ||
| 353 | if (!rbd_opts) | ||
| 354 | return -ENOMEM; | ||
| 355 | |||
| 356 | rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT; | ||
| 279 | 357 | ||
| 280 | ret = ceph_parse_options(&opt, options, mon_addr, | 358 | ret = ceph_parse_options(&opt, options, mon_addr, |
| 281 | mon_addr + strlen(mon_addr), NULL, NULL); | 359 | mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts); |
| 282 | if (ret < 0) | 360 | if (ret < 0) |
| 283 | return ret; | 361 | goto done_err; |
| 284 | 362 | ||
| 285 | spin_lock(&node_lock); | 363 | spin_lock(&node_lock); |
| 286 | rbdc = __rbd_client_find(opt); | 364 | rbdc = __rbd_client_find(opt); |
| @@ -296,13 +374,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, | |||
| 296 | } | 374 | } |
| 297 | spin_unlock(&node_lock); | 375 | spin_unlock(&node_lock); |
| 298 | 376 | ||
| 299 | rbdc = rbd_client_create(opt); | 377 | rbdc = rbd_client_create(opt, rbd_opts); |
| 300 | if (IS_ERR(rbdc)) | 378 | if (IS_ERR(rbdc)) { |
| 301 | return PTR_ERR(rbdc); | 379 | ret = PTR_ERR(rbdc); |
| 380 | goto done_err; | ||
| 381 | } | ||
| 302 | 382 | ||
| 303 | rbd_dev->rbd_client = rbdc; | 383 | rbd_dev->rbd_client = rbdc; |
| 304 | rbd_dev->client = rbdc->client; | 384 | rbd_dev->client = rbdc->client; |
| 305 | return 0; | 385 | return 0; |
| 386 | done_err: | ||
| 387 | kfree(rbd_opts); | ||
| 388 | return ret; | ||
| 306 | } | 389 | } |
