Skip to content

Commit 7b19b4d

Browse files
vshankaridryomov
authored andcommitted
ceph: new device mount syntax
Old mount device syntax (source) has the following problems: - mounts to the same cluster but with different fsnames and/or creds have identical device string which can confuse xfstests. - Userspace mount helper tool resolves monitor addresses and fill in mon addrs automatically, but that means the device shown in /proc/mounts is different than what was used for mounting. New device syntax is as follows: [email protected]=/path Note, there is no "monitor address" in the device string. That gets passed in as mount option. This keeps the device string same when monitor addresses change (on remounts). Also note that the userspace mount helper tool is backward compatible. I.e., the mount helper will fallback to using old syntax after trying to mount with the new syntax. [ idryomov: drop CEPH_MON_ADDR_MNTOPT_DELIM ] Signed-off-by: Venky Shankar <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 4153c7f commit 7b19b4d

File tree

2 files changed

+134
-10
lines changed

2 files changed

+134
-10
lines changed

fs/ceph/super.c

Lines changed: 131 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ enum {
146146
Opt_mds_namespace,
147147
Opt_recover_session,
148148
Opt_source,
149+
Opt_mon_addr,
149150
/* string args above */
150151
Opt_dirstat,
151152
Opt_rbytes,
@@ -197,6 +198,7 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
197198
fsparam_u32 ("rsize", Opt_rsize),
198199
fsparam_string ("snapdirname", Opt_snapdirname),
199200
fsparam_string ("source", Opt_source),
201+
fsparam_string ("mon_addr", Opt_mon_addr),
200202
fsparam_u32 ("wsize", Opt_wsize),
201203
fsparam_flag_no ("wsync", Opt_wsync),
202204
{}
@@ -228,9 +230,92 @@ static void canonicalize_path(char *path)
228230
}
229231

230232
/*
231-
* Parse the source parameter. Distinguish the server list from the path.
233+
* Check if the mds namespace in ceph_mount_options matches
234+
* the passed in namespace string. First time match (when
235+
* ->mds_namespace is NULL) is treated specially, since
236+
* ->mds_namespace needs to be initialized by the caller.
237+
*/
238+
static int namespace_equals(struct ceph_mount_options *fsopt,
239+
const char *namespace, size_t len)
240+
{
241+
return !(fsopt->mds_namespace &&
242+
(strlen(fsopt->mds_namespace) != len ||
243+
strncmp(fsopt->mds_namespace, namespace, len)));
244+
}
245+
246+
static int ceph_parse_old_source(const char *dev_name, const char *dev_name_end,
247+
struct fs_context *fc)
248+
{
249+
int r;
250+
struct ceph_parse_opts_ctx *pctx = fc->fs_private;
251+
struct ceph_mount_options *fsopt = pctx->opts;
252+
253+
if (*dev_name_end != ':')
254+
return invalfc(fc, "separator ':' missing in source");
255+
256+
r = ceph_parse_mon_ips(dev_name, dev_name_end - dev_name,
257+
pctx->copts, fc->log.log, ',');
258+
if (r)
259+
return r;
260+
261+
fsopt->new_dev_syntax = false;
262+
return 0;
263+
}
264+
265+
static int ceph_parse_new_source(const char *dev_name, const char *dev_name_end,
266+
struct fs_context *fc)
267+
{
268+
size_t len;
269+
struct ceph_fsid fsid;
270+
struct ceph_parse_opts_ctx *pctx = fc->fs_private;
271+
struct ceph_mount_options *fsopt = pctx->opts;
272+
char *fsid_start, *fs_name_start;
273+
274+
if (*dev_name_end != '=') {
275+
dout("separator '=' missing in source");
276+
return -EINVAL;
277+
}
278+
279+
fsid_start = strchr(dev_name, '@');
280+
if (!fsid_start)
281+
return invalfc(fc, "missing cluster fsid");
282+
++fsid_start; /* start of cluster fsid */
283+
284+
fs_name_start = strchr(fsid_start, '.');
285+
if (!fs_name_start)
286+
return invalfc(fc, "missing file system name");
287+
288+
if (ceph_parse_fsid(fsid_start, &fsid))
289+
return invalfc(fc, "Invalid FSID");
290+
291+
++fs_name_start; /* start of file system name */
292+
len = dev_name_end - fs_name_start;
293+
294+
if (!namespace_equals(fsopt, fs_name_start, len))
295+
return invalfc(fc, "Mismatching mds_namespace");
296+
kfree(fsopt->mds_namespace);
297+
fsopt->mds_namespace = kstrndup(fs_name_start, len, GFP_KERNEL);
298+
if (!fsopt->mds_namespace)
299+
return -ENOMEM;
300+
dout("file system (mds namespace) '%s'\n", fsopt->mds_namespace);
301+
302+
fsopt->new_dev_syntax = true;
303+
return 0;
304+
}
305+
306+
/*
307+
* Parse the source parameter for new device format. Distinguish the device
308+
* spec from the path. Try parsing new device format and fallback to old
309+
* format if needed.
310+
*
311+
* New device syntax will looks like:
312+
* <device_spec>=/<path>
313+
* where
314+
* <device_spec> is [email protected]
315+
* <path> is optional, but if present must begin with '/'
316+
* (monitor addresses are passed via mount option)
232317
*
233-
* The source will look like:
318+
* Old device syntax is:
234319
* <server_spec>[,<server_spec>...]:[<path>]
235320
* where
236321
* <server_spec> is <ip>[:<port>]
@@ -263,24 +348,44 @@ static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
263348
dev_name_end = dev_name + strlen(dev_name);
264349
}
265350

266-
dev_name_end--; /* back up to ':' separator */
267-
if (dev_name_end < dev_name || *dev_name_end != ':')
268-
return invalfc(fc, "No path or : separator in source");
351+
dev_name_end--; /* back up to separator */
352+
if (dev_name_end < dev_name)
353+
return invalfc(fc, "Path missing in source");
269354

270355
dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
271356
if (fsopt->server_path)
272357
dout("server path '%s'\n", fsopt->server_path);
273358

274-
ret = ceph_parse_mon_ips(param->string, dev_name_end - dev_name,
275-
pctx->copts, fc->log.log, ',');
276-
if (ret)
277-
return ret;
359+
dout("trying new device syntax");
360+
ret = ceph_parse_new_source(dev_name, dev_name_end, fc);
361+
if (ret) {
362+
if (ret != -EINVAL)
363+
return ret;
364+
dout("trying old device syntax");
365+
ret = ceph_parse_old_source(dev_name, dev_name_end, fc);
366+
if (ret)
367+
return ret;
368+
}
278369

279370
fc->source = param->string;
280371
param->string = NULL;
281372
return 0;
282373
}
283374

375+
static int ceph_parse_mon_addr(struct fs_parameter *param,
376+
struct fs_context *fc)
377+
{
378+
struct ceph_parse_opts_ctx *pctx = fc->fs_private;
379+
struct ceph_mount_options *fsopt = pctx->opts;
380+
381+
kfree(fsopt->mon_addr);
382+
fsopt->mon_addr = param->string;
383+
param->string = NULL;
384+
385+
return ceph_parse_mon_ips(fsopt->mon_addr, strlen(fsopt->mon_addr),
386+
pctx->copts, fc->log.log, '/');
387+
}
388+
284389
static int ceph_parse_mount_param(struct fs_context *fc,
285390
struct fs_parameter *param)
286391
{
@@ -306,6 +411,8 @@ static int ceph_parse_mount_param(struct fs_context *fc,
306411
param->string = NULL;
307412
break;
308413
case Opt_mds_namespace:
414+
if (!namespace_equals(fsopt, param->string, strlen(param->string)))
415+
return invalfc(fc, "Mismatching mds_namespace");
309416
kfree(fsopt->mds_namespace);
310417
fsopt->mds_namespace = param->string;
311418
param->string = NULL;
@@ -323,6 +430,8 @@ static int ceph_parse_mount_param(struct fs_context *fc,
323430
if (fc->source)
324431
return invalfc(fc, "Multiple sources specified");
325432
return ceph_parse_source(param, fc);
433+
case Opt_mon_addr:
434+
return ceph_parse_mon_addr(param, fc);
326435
case Opt_wsize:
327436
if (result.uint_32 < PAGE_SIZE ||
328437
result.uint_32 > CEPH_MAX_WRITE_SIZE)
@@ -474,6 +583,7 @@ static void destroy_mount_options(struct ceph_mount_options *args)
474583
kfree(args->mds_namespace);
475584
kfree(args->server_path);
476585
kfree(args->fscache_uniq);
586+
kfree(args->mon_addr);
477587
kfree(args);
478588
}
479589

@@ -517,6 +627,10 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
517627
if (ret)
518628
return ret;
519629

630+
ret = strcmp_null(fsopt1->mon_addr, fsopt2->mon_addr);
631+
if (ret)
632+
return ret;
633+
520634
return ceph_compare_options(new_opt, fsc->client);
521635
}
522636

@@ -572,9 +686,13 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
572686
if ((fsopt->flags & CEPH_MOUNT_OPT_NOCOPYFROM) == 0)
573687
seq_puts(m, ",copyfrom");
574688

575-
if (fsopt->mds_namespace)
689+
/* dump mds_namespace when old device syntax is in use */
690+
if (fsopt->mds_namespace && !fsopt->new_dev_syntax)
576691
seq_show_option(m, "mds_namespace", fsopt->mds_namespace);
577692

693+
if (fsopt->mon_addr)
694+
seq_printf(m, ",mon_addr=%s", fsopt->mon_addr);
695+
578696
if (fsopt->flags & CEPH_MOUNT_OPT_CLEANRECOVER)
579697
seq_show_option(m, "recover_session", "clean");
580698

@@ -1060,6 +1178,7 @@ static int ceph_setup_bdi(struct super_block *sb, struct ceph_fs_client *fsc)
10601178
static int ceph_get_tree(struct fs_context *fc)
10611179
{
10621180
struct ceph_parse_opts_ctx *pctx = fc->fs_private;
1181+
struct ceph_mount_options *fsopt = pctx->opts;
10631182
struct super_block *sb;
10641183
struct ceph_fs_client *fsc;
10651184
struct dentry *res;
@@ -1071,6 +1190,8 @@ static int ceph_get_tree(struct fs_context *fc)
10711190

10721191
if (!fc->source)
10731192
return invalfc(fc, "No source");
1193+
if (fsopt->new_dev_syntax && !fsopt->mon_addr)
1194+
return invalfc(fc, "No monitor address");
10741195

10751196
/* create client (which we may/may not use) */
10761197
fsc = create_fs_client(pctx->opts, pctx->copts);

fs/ceph/super.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ struct ceph_mount_options {
8989
unsigned int max_readdir; /* max readdir result (entries) */
9090
unsigned int max_readdir_bytes; /* max readdir result (bytes) */
9191

92+
bool new_dev_syntax;
93+
9294
/*
9395
* everything above this point can be memcmp'd; everything below
9496
* is handled in compare_mount_options()
@@ -98,6 +100,7 @@ struct ceph_mount_options {
98100
char *mds_namespace; /* default NULL */
99101
char *server_path; /* default NULL (means "/") */
100102
char *fscache_uniq; /* default NULL */
103+
char *mon_addr;
101104
};
102105

103106
struct ceph_fs_client {

0 commit comments

Comments
 (0)