From 404b6c45981cf7e706b148b085cfc23896b7c530 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 24 Jul 2008 16:18:35 -0700 Subject: [PATCH] kclient: fix multiple mount points from same client; serialize mount attempts --- src/kernel/super.c | 125 ++++++++++++++++++++++++--------------------- src/kernel/super.h | 1 + 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/kernel/super.c b/src/kernel/super.c index 09a25aa479c1a..d624a8a67f9b2 100644 --- a/src/kernel/super.c +++ b/src/kernel/super.c @@ -566,65 +566,66 @@ static int parse_mount_args(int flags, char *options, const char *dev_name, */ struct ceph_client *ceph_create_client(void) { - struct ceph_client *cl; + struct ceph_client *client; int err = -ENOMEM; - cl = kzalloc(sizeof(*cl), GFP_KERNEL); - if (cl == NULL) + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (client == NULL) return ERR_PTR(-ENOMEM); - init_waitqueue_head(&cl->mount_wq); - spin_lock_init(&cl->sb_lock); + mutex_init(&client->mount_mutex); + + init_waitqueue_head(&client->mount_wq); + spin_lock_init(&client->sb_lock); - cl->sb = 0; - cl->mount_state = CEPH_MOUNT_MOUNTING; - cl->whoami = -1; + client->sb = 0; + client->mount_state = CEPH_MOUNT_MOUNTING; + client->whoami = -1; - cl->msgr = 0; + client->msgr = 0; - cl->wb_wq = create_workqueue("ceph-writeback"); - if (cl->wb_wq == 0) + client->wb_wq = create_workqueue("ceph-writeback"); + if (client->wb_wq == 0) goto fail; - cl->trunc_wq = create_workqueue("ceph-trunc"); - if (cl->trunc_wq == 0) + client->trunc_wq = create_workqueue("ceph-trunc"); + if (client->trunc_wq == 0) goto fail; /* subsystems */ - err = ceph_monc_init(&cl->monc, cl); + err = ceph_monc_init(&client->monc, client); if (err < 0) return ERR_PTR(err); - ceph_mdsc_init(&cl->mdsc, cl); - ceph_osdc_init(&cl->osdc, cl); + ceph_mdsc_init(&client->mdsc, client); + ceph_osdc_init(&client->osdc, client); - return cl; + return client; fail: - /* fixme: use type->init() eventually */ return ERR_PTR(-ENOMEM); } -void ceph_destroy_client(struct ceph_client *cl) +void ceph_destroy_client(struct ceph_client *client) { - dout(10, "destroy_client %p\n", cl); + dout(10, "destroy_client %p\n", client); /* unmount */ /* ... */ - ceph_monc_stop(&cl->monc); - ceph_osdc_stop(&cl->osdc); + ceph_monc_stop(&client->monc); + ceph_osdc_stop(&client->osdc); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) - if (cl->client_kobj) - kobject_put(cl->client_kobj); + if (client->client_kobj) + kobject_put(client->client_kobj); #endif - if (cl->wb_wq) - destroy_workqueue(cl->wb_wq); - if (cl->trunc_wq) - destroy_workqueue(cl->trunc_wq); - if (cl->msgr) - ceph_messenger_destroy(cl->msgr); - kfree(cl); - dout(10, "destroy_client %p done\n", cl); + if (client->wb_wq) + destroy_workqueue(client->wb_wq); + if (client->trunc_wq) + destroy_workqueue(client->trunc_wq); + if (client->msgr) + ceph_messenger_destroy(client->msgr); + kfree(client); + dout(10, "destroy_client %p done\n", client); } static int have_all_maps(struct ceph_client *client) @@ -678,27 +679,37 @@ int ceph_mount(struct ceph_client *client, struct vfsmount *mnt) char r; dout(10, "mount start\n"); + mutex_lock(&client->mount_mutex); /* messenger */ - if (client->mount_args.flags & CEPH_MOUNT_MYIP) - myaddr = &client->mount_args.my_addr; - client->msgr = ceph_messenger_create(myaddr); - if (IS_ERR(client->msgr)) { - err = PTR_ERR(client->msgr); - client->msgr = 0; - return err; + if (client->msgr == NULL) { + if (client->mount_args.flags & CEPH_MOUNT_MYIP) + myaddr = &client->mount_args.my_addr; + client->msgr = ceph_messenger_create(myaddr); + if (IS_ERR(client->msgr)) { + err = PTR_ERR(client->msgr); + client->msgr = 0; + goto out; + } + client->msgr->parent = client; + client->msgr->dispatch = ceph_dispatch; + client->msgr->prepare_pages = ceph_osdc_prepare_pages; + client->msgr->peer_reset = ceph_peer_reset; } - client->msgr->parent = client; - client->msgr->dispatch = ceph_dispatch; - client->msgr->prepare_pages = ceph_osdc_prepare_pages; - client->msgr->peer_reset = ceph_peer_reset; - - while (1) { + + while (!have_all_maps(client)) { + err = -EIO; + if (attempts == 0) + goto out; + dout(10, "mount sending mount request, %d attempts left\n", + attempts--); get_random_bytes(&r, 1); which = r % client->mount_args.num_mon; mount_msg = ceph_msg_new(CEPH_MSG_CLIENT_MOUNT, 0, 0, 0, 0); - if (IS_ERR(mount_msg)) - return PTR_ERR(mount_msg); + if (IS_ERR(mount_msg)) { + err = PTR_ERR(mount_msg); + goto out; + } mount_msg->hdr.dst.name.type = cpu_to_le32(CEPH_ENTITY_TYPE_MON); mount_msg->hdr.dst.name.num = cpu_to_le32(which); @@ -715,24 +726,24 @@ int ceph_mount(struct ceph_client *client, struct vfsmount *mnt) 6*HZ); dout(10, "mount wait got %d\n", err); if (err == -EINTR) - return err; - if (have_all_maps(client)) - break; /* success */ - dout(10, "mount still waiting for mount, attempts=%d\n", - attempts); - if (--attempts == 0) - return -EIO; + goto out; } dout(30, "mount opening base mountpoint\n"); root = open_root_dentry(client); - if (IS_ERR(root)) - return PTR_ERR(root); + if (IS_ERR(root)) { + err = PTR_ERR(root); + goto out; + } mnt->mnt_root = root; mnt->mnt_sb = client->sb; client->mount_state = CEPH_MOUNT_MOUNTED; dout(10, "mount success\n"); - return 0; + err = 0; + +out: + mutex_unlock(&client->mount_mutex); + return err; } diff --git a/src/kernel/super.h b/src/kernel/super.h index 5dea66ef1498a..f08f3589f9c62 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -127,6 +127,7 @@ extern struct kobject *ceph_kobj; struct ceph_client { __u32 whoami; /* my client number */ + struct mutex mount_mutex; /* serialize mount attempts */ struct ceph_mount_args mount_args; struct ceph_fsid fsid; -- 2.39.5