From 6b8051855d983db8480ff1ea1b02ef2b49203c22 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 27 Oct 2009 11:50:50 -0700 Subject: [PATCH] ceph: allocate and parse mount args before client instance This simplifies much of the error handling during mount. It also means that we have the mount args before client creation, and we can initialize based on those options. Signed-off-by: Sage Weil --- fs/ceph/addr.c | 4 +- fs/ceph/caps.c | 4 +- fs/ceph/dir.c | 7 +-- fs/ceph/mds_client.c | 6 +-- fs/ceph/mon_client.c | 38 ++++++++++++++++ fs/ceph/osd_client.c | 6 +-- fs/ceph/super.c | 106 ++++++++++++++++++++----------------------- fs/ceph/super.h | 8 ++-- 8 files changed, 105 insertions(+), 74 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index c7d673ffe023..bf535815592d 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -600,8 +600,8 @@ static int ceph_writepages_start(struct address_space *mapping, pr_warning("writepage_start %p on forced umount\n", inode); return -EIO; /* we're in a forced umount, don't write! */ } - if (client->mount_args.wsize && client->mount_args.wsize < wsize) - wsize = client->mount_args.wsize; + if (client->mount_args->wsize && client->mount_args->wsize < wsize) + wsize = client->mount_args->wsize; if (wsize < PAGE_CACHE_SIZE) wsize = PAGE_CACHE_SIZE; max_pages_ever = wsize >> PAGE_CACHE_SHIFT; diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 7d166182e98d..8b863dbec70c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -270,7 +270,7 @@ static void put_cap(struct ceph_cap *cap, * lots of free/alloc churn. */ if (caps_avail_count >= caps_reserve_count + - ceph_client(cap->ci->vfs_inode.i_sb)->mount_args.max_readdir) { + ceph_client(cap->ci->vfs_inode.i_sb)->mount_args->max_readdir) { caps_total_count--; kmem_cache_free(ceph_cap_cachep, cap); } else { @@ -388,7 +388,7 @@ static void __insert_cap_node(struct ceph_inode_info *ci, static void __cap_set_timeouts(struct ceph_mds_client *mdsc, struct ceph_inode_info *ci) { - struct ceph_mount_args *ma = &mdsc->client->mount_args; + struct ceph_mount_args *ma = mdsc->client->mount_args; ci->i_hold_caps_min = round_jiffies(jiffies + ma->caps_wanted_delay_min * HZ); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 7bb8db524e58..4f7467961b09 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -225,7 +225,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) int err; u32 ftype; struct ceph_mds_reply_info_parsed *rinfo; - const int max_entries = client->mount_args.max_readdir; + const int max_entries = client->mount_args->max_readdir; dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off); if (fi->at_end) @@ -479,7 +479,8 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, /* .snap dir? */ if (err == -ENOENT && ceph_vino(parent).ino != CEPH_INO_ROOT && /* no .snap in root dir */ - strcmp(dentry->d_name.name, client->mount_args.snapdir_name) == 0) { + strcmp(dentry->d_name.name, + client->mount_args->snapdir_name) == 0) { struct inode *inode = ceph_get_snapdir(parent); dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n", dentry, dentry->d_name.len, dentry->d_name.name, inode); @@ -550,7 +551,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, spin_lock(&dir->i_lock); dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags); if (strncmp(dentry->d_name.name, - client->mount_args.snapdir_name, + client->mount_args->snapdir_name, dentry->d_name.len) && (ci->i_ceph_flags & CEPH_I_COMPLETE) && (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 12d66c0572ac..210cb6623ea2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -943,7 +943,7 @@ static int add_cap_releases(struct ceph_mds_client *mdsc, int err = -ENOMEM; if (extra < 0) - extra = mdsc->client->mount_args.cap_release_safety; + extra = mdsc->client->mount_args->cap_release_safety; spin_lock(&session->s_cap_lock); @@ -2601,7 +2601,7 @@ static void wait_requests(struct ceph_mds_client *mdsc) mutex_unlock(&mdsc->mutex); dout("wait_requests waiting for requests\n"); wait_for_completion_timeout(&mdsc->safe_umount_waiters, - client->mount_args.mount_timeout * HZ); + client->mount_args->mount_timeout * HZ); mutex_lock(&mdsc->mutex); /* tear down remaining requests */ @@ -2693,7 +2693,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) int i; int n; struct ceph_client *client = mdsc->client; - unsigned long started, timeout = client->mount_args.mount_timeout * HZ; + unsigned long started, timeout = client->mount_args->mount_timeout * HZ; dout("close_sessions\n"); diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c index e6e954cac6b9..61263c99c6a8 100644 --- a/fs/ceph/mon_client.c +++ b/fs/ceph/mon_client.c @@ -527,6 +527,40 @@ static void delayed_work(struct work_struct *work) mutex_unlock(&monc->mutex); } +/* + * On startup, we build a temporary monmap populated with the IPs + * provided by mount(2). + */ +static int build_initial_monmap(struct ceph_mon_client *monc) +{ + struct ceph_mount_args *args = monc->client->mount_args; + struct ceph_entity_addr *mon_addr = args->mon_addr; + int num_mon = args->num_mon; + int i; + + /* build initial monmap */ + monc->monmap = kzalloc(sizeof(*monc->monmap) + + num_mon*sizeof(monc->monmap->mon_inst[0]), + GFP_KERNEL); + if (!monc->monmap) + return -ENOMEM; + for (i = 0; i < num_mon; i++) { + monc->monmap->mon_inst[i].addr = mon_addr[i]; + monc->monmap->mon_inst[i].addr.erank = 0; + monc->monmap->mon_inst[i].addr.nonce = 0; + monc->monmap->mon_inst[i].name.type = + CEPH_ENTITY_TYPE_MON; + monc->monmap->mon_inst[i].name.num = cpu_to_le64(i); + } + monc->monmap->num_mon = num_mon; + + /* release addr memory */ + kfree(args->mon_addr); + args->mon_addr = NULL; + args->num_mon = 0; + return 0; +} + int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) { int err = 0; @@ -537,6 +571,10 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) monc->monmap = NULL; mutex_init(&monc->mutex); + err = build_initial_monmap(monc); + if (err) + goto out; + monc->con = NULL; /* msg pools */ diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index 0a254054a82a..7dc0f6299a52 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -444,7 +444,7 @@ static void register_request(struct ceph_osd_client *osdc, osdc->num_requests++; req->r_timeout_stamp = - jiffies + osdc->client->mount_args.osd_timeout*HZ; + jiffies + osdc->client->mount_args->osd_timeout*HZ; if (osdc->num_requests == 1) { osdc->timeout_tid = req->r_tid; @@ -609,7 +609,7 @@ static int __send_request(struct ceph_osd_client *osdc, reqhead->flags |= cpu_to_le32(req->r_flags); /* e.g., RETRY */ reqhead->reassert_version = req->r_reassert_version; - req->r_timeout_stamp = jiffies+osdc->client->mount_args.osd_timeout*HZ; + req->r_timeout_stamp = jiffies+osdc->client->mount_args->osd_timeout*HZ; ceph_msg_get(req->r_request); /* send consumes a ref */ ceph_con_send(&req->r_osd->o_con, req->r_request); @@ -632,7 +632,7 @@ static void handle_timeout(struct work_struct *work) container_of(work, struct ceph_osd_client, timeout_work.work); struct ceph_osd_request *req; struct ceph_osd *osd; - unsigned long timeout = osdc->client->mount_args.osd_timeout * HZ; + unsigned long timeout = osdc->client->mount_args->osd_timeout * HZ; unsigned long next_timeout = timeout + jiffies; struct rb_node *p; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index b094f5003ef8..9b7815dfc035 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -110,7 +110,7 @@ static int ceph_syncfs(struct super_block *sb, int wait) static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) { struct ceph_client *client = ceph_sb_to_client(mnt->mnt_sb); - struct ceph_mount_args *args = &client->mount_args; + struct ceph_mount_args *args = client->mount_args; if (args->flags & CEPH_OPT_FSID) seq_printf(m, ",fsidmajor=%llu,fsidminor%llu", @@ -307,24 +307,24 @@ static match_table_t arg_tokens = { }; -static int parse_mount_args(struct ceph_client *client, - int flags, char *options, const char *dev_name, - const char **path) +static struct ceph_mount_args *parse_mount_args(int flags, char *options, + const char *dev_name, + const char **path) { - struct ceph_mount_args *args = &client->mount_args; + struct ceph_mount_args *args; const char *c; - int err; + int err = -ENOMEM; substring_t argstr[MAX_OPT_ARGS]; - int num_mon; - struct ceph_entity_addr *mon_addr; - int i; - dout("parse_mount_args dev_name '%s'\n", dev_name); - memset(args, 0, sizeof(*args)); + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return ERR_PTR(-ENOMEM); + args->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*args->mon_addr), + GFP_KERNEL); + if (!args->mon_addr) + goto out; - mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*mon_addr), GFP_KERNEL); - if (!mon_addr) - return -ENOMEM; + dout("parse_mount_args %p, dev_name '%s'\n", args, dev_name); /* start with defaults */ args->sb_flags = flags; @@ -350,29 +350,11 @@ static int parse_mount_args(struct ceph_client *client, } /* get mon ip(s) */ - err = ceph_parse_ips(dev_name, *path, mon_addr, - CEPH_MAX_MON, &num_mon); + err = ceph_parse_ips(dev_name, *path, args->mon_addr, + CEPH_MAX_MON, &args->num_mon); if (err < 0) goto out; - /* build initial monmap */ - err = -ENOMEM; - client->monc.monmap = kzalloc(sizeof(*client->monc.monmap) + - num_mon*sizeof(client->monc.monmap->mon_inst[0]), - GFP_KERNEL); - if (!client->monc.monmap) - goto out; - for (i = 0; i < num_mon; i++) { - client->monc.monmap->mon_inst[i].addr = mon_addr[i]; - client->monc.monmap->mon_inst[i].addr.erank = 0; - client->monc.monmap->mon_inst[i].addr.nonce = 0; - client->monc.monmap->mon_inst[i].name.type = - CEPH_ENTITY_TYPE_MON; - client->monc.monmap->mon_inst[i].name.num = cpu_to_le64(i); - } - client->monc.monmap->num_mon = num_mon; - memset(&args->my_addr.in_addr, 0, sizeof(args->my_addr.in_addr)); - /* path on server */ *path += 2; dout("server path '%s'\n", *path); @@ -415,7 +397,7 @@ static int parse_mount_args(struct ceph_client *client, &args->my_addr, 1, NULL); if (err < 0) - return err; + goto out; args->flags |= CEPH_OPT_MYIP; break; @@ -481,25 +463,28 @@ static int parse_mount_args(struct ceph_client *client, BUG_ON(token); } } - err = 0; + return args; out: - kfree(mon_addr); - return err; + kfree(args->mon_addr); + kfree(args); + return ERR_PTR(err); } -static void release_mount_args(struct ceph_mount_args *args) +static void destroy_mount_args(struct ceph_mount_args *args) { + dout("destroy_mount_args %p\n", args); kfree(args->snapdir_name); args->snapdir_name = NULL; kfree(args->secret); args->secret = NULL; + kfree(args); } /* * create a fresh client instance */ -static struct ceph_client *ceph_create_client(void) +static struct ceph_client *ceph_create_client(struct ceph_mount_args *args) { struct ceph_client *client; int err = -ENOMEM; @@ -515,6 +500,7 @@ static struct ceph_client *ceph_create_client(void) client->sb = NULL; client->mount_state = CEPH_MOUNT_MOUNTING; client->whoami = -1; + client->mount_args = args; client->msgr = NULL; @@ -577,7 +563,7 @@ static void ceph_destroy_client(struct ceph_client *client) if (client->wb_pagevec_pool) mempool_destroy(client->wb_pagevec_pool); - release_mount_args(&client->mount_args); + destroy_mount_args(client->mount_args); kfree(client); dout("destroy_client %p done\n", client); @@ -613,7 +599,7 @@ static struct dentry *open_root_dentry(struct ceph_client *client, req->r_ino1.ino = CEPH_INO_ROOT; req->r_ino1.snap = CEPH_NOSNAP; req->r_started = started; - req->r_timeout = client->mount_args.mount_timeout * HZ; + req->r_timeout = client->mount_args->mount_timeout * HZ; req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); @@ -641,7 +627,7 @@ static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt, { struct ceph_entity_addr *myaddr = NULL; int err; - unsigned long timeout = client->mount_args.mount_timeout * HZ; + unsigned long timeout = client->mount_args->mount_timeout * HZ; unsigned long started = jiffies; /* note the start time */ struct dentry *root; @@ -651,7 +637,7 @@ static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt, /* initialize the messenger */ if (client->msgr == NULL) { if (ceph_test_opt(client, MYIP)) - myaddr = &client->mount_args.my_addr; + myaddr = &client->mount_args->my_addr; client->msgr = ceph_messenger_create(myaddr); if (IS_ERR(client->msgr)) { err = PTR_ERR(client->msgr); @@ -727,7 +713,7 @@ static int ceph_set_super(struct super_block *s, void *data) dout("set_super %p data %p\n", s, data); - s->s_flags = client->mount_args.sb_flags; + s->s_flags = client->mount_args->sb_flags; s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ s->s_fs_info = client; @@ -756,7 +742,7 @@ fail: static int ceph_compare_super(struct super_block *sb, void *data) { struct ceph_client *new = data; - struct ceph_mount_args *args = &new->mount_args; + struct ceph_mount_args *args = new->mount_args; struct ceph_client *other = ceph_sb_to_client(sb); int i; @@ -778,7 +764,7 @@ static int ceph_compare_super(struct super_block *sb, void *data) } dout("mon ip matches existing sb %p\n", sb); } - if (args->sb_flags != other->mount_args.sb_flags) { + if (args->sb_flags != other->mount_args->sb_flags) { dout("flags differ\n"); return 0; } @@ -798,9 +784,9 @@ static int ceph_init_bdi(struct super_block *sb, struct ceph_client *client) sb->s_bdi = &client->backing_dev_info; /* set ra_pages based on rsize mount option? */ - if (client->mount_args.rsize >= PAGE_CACHE_SIZE) + if (client->mount_args->rsize >= PAGE_CACHE_SIZE) client->backing_dev_info.ra_pages = - (client->mount_args.rsize + PAGE_CACHE_SIZE - 1) + (client->mount_args->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_SHIFT; err = bdi_register_dev(&client->backing_dev_info, sb->s_dev); @@ -816,19 +802,23 @@ static int ceph_get_sb(struct file_system_type *fs_type, int err; int (*compare_super)(struct super_block *, void *) = ceph_compare_super; const char *path = 0; + struct ceph_mount_args *args; dout("ceph_get_sb\n"); + args = parse_mount_args(flags, data, dev_name, &path); + if (IS_ERR(args)) { + err = PTR_ERR(args); + goto out_final; + } /* create client (which we may/may not use) */ - client = ceph_create_client(); - if (IS_ERR(client)) - return PTR_ERR(client); + client = ceph_create_client(args); + if (IS_ERR(client)) { + err = PTR_ERR(client); + goto out_final; + } - err = parse_mount_args(client, flags, data, dev_name, &path); - if (err < 0) - goto out; - - if (client->mount_args.flags & CEPH_OPT_NOSHARE) + if (client->mount_args->flags & CEPH_OPT_NOSHARE) compare_super = NULL; sb = sget(fs_type, compare_super, ceph_set_super, client); if (IS_ERR(sb)) { @@ -846,7 +836,7 @@ static int ceph_get_sb(struct file_system_type *fs_type, /* set up mempools */ err = -ENOMEM; client->wb_pagevec_pool = mempool_create_kmalloc_pool(10, - client->mount_args.wsize >> PAGE_CACHE_SHIFT); + client->mount_args->wsize >> PAGE_CACHE_SHIFT); if (!client->wb_pagevec_pool) goto out_splat; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3af42d9097ec..a3d4943581d0 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -42,13 +42,15 @@ #define CEPH_OPT_DEFAULT (CEPH_OPT_RBYTES) #define ceph_set_opt(client, opt) \ - (client)->mount_args.flags |= CEPH_OPT_##opt; + (client)->mount_args->flags |= CEPH_OPT_##opt; #define ceph_test_opt(client, opt) \ - (!!((client)->mount_args.flags & CEPH_OPT_##opt)) + (!!((client)->mount_args->flags & CEPH_OPT_##opt)) struct ceph_mount_args { int sb_flags; + int num_mon; + struct ceph_entity_addr *mon_addr; int flags; int mount_timeout; int caps_wanted_delay_min, caps_wanted_delay_max; @@ -115,7 +117,7 @@ struct ceph_client { struct dentry *debugfs_dir, *debugfs_dentry_lru, *debugfs_caps; struct mutex mount_mutex; /* serialize mount attempts */ - struct ceph_mount_args mount_args; + struct ceph_mount_args *mount_args; struct ceph_fsid fsid; struct super_block *sb;