aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2012-08-09 13:33:26 -0400
committerAlex Elder <elder@inktank.com>2012-10-01 15:30:49 -0400
commitc98f533c9497e285109a047bfb955d683f33f7e4 (patch)
tree2f47418cd404a20351beedadb1b2712302bbd6fc /fs
parent4156d998409be065aa8141b6bd2c6f18be1b21e9 (diff)
ceph: let path portion of mount "device" be optional
A recent change to /sbin/mountall causes any trailing '/' character in the "device" (or fs_spec) field in /etc/fstab to be stripped. As a result, an entry for a ceph mount that intends to mount the root of the name space ends up with now path portion, and the ceph mount option processing code rejects this. That is, an entry in /etc/fstab like: cephserver:port:/ /mnt ceph defaults 0 0 provides to the ceph code just "cephserver:port:" as the "device," and that gets rejected. Although this is a bug in /sbin/mountall, we can have the ceph mount code support an empty/nonexistent path, interpreting it to mean the root of the name space. RFC 5952 offers recommendations for how to express IPv6 addresses, and recommends the usage found in RFC 3986 (which specifies the format for URI's) for representing both IPv4 and IPv6 addresses that include port numbers. (See in particular the definition of "authority" found in the Appendix of RFC 3986.) According to those standards, no host specification will ever contain a '/' character. As a result, it is sufficient to scan a provided "device" from an /etc/fstab entry for the first '/' character, and if it's found, treat that as the beginning of the path. If no '/' character is present, we can treat the entire string as the monitor host specification(s), and assume the path to be the root of the name space. We'll still require a ':' to separate the host portion from the (possibly empty) path portion. This means that we can more formally define how ceph will interpret the "device" it's provided when processing a mount request: "device" will look like: <server_spec>[,<server_spec>...]:[<path>] where <server_spec> is <ip>[:<port>] <path> is optional, but if present must begin with '/' This addresses http://tracker.newdream.net/issues/2919 Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Dan Mick <dan.mick@inktank.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/super.c37
1 files changed, 26 insertions, 11 deletions
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index b982239f38f9..2f586b0e5e0f 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -307,7 +307,10 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
307{ 307{
308 struct ceph_mount_options *fsopt; 308 struct ceph_mount_options *fsopt;
309 const char *dev_name_end; 309 const char *dev_name_end;
310 int err = -ENOMEM; 310 int err;
311
312 if (!dev_name || !*dev_name)
313 return -EINVAL;
311 314
312 fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL); 315 fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
313 if (!fsopt) 316 if (!fsopt)
@@ -328,21 +331,33 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
328 fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; 331 fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
329 fsopt->congestion_kb = default_congestion_kb(); 332 fsopt->congestion_kb = default_congestion_kb();
330 333
331 /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */ 334 /*
335 * Distinguish the server list from the path in "dev_name".
336 * Internally we do not include the leading '/' in the path.
337 *
338 * "dev_name" will look like:
339 * <server_spec>[,<server_spec>...]:[<path>]
340 * where
341 * <server_spec> is <ip>[:<port>]
342 * <path> is optional, but if present must begin with '/'
343 */
344 dev_name_end = strchr(dev_name, '/');
345 if (dev_name_end) {
346 /* skip over leading '/' for path */
347 *path = dev_name_end + 1;
348 } else {
349 /* path is empty */
350 dev_name_end = dev_name + strlen(dev_name);
351 *path = dev_name_end;
352 }
332 err = -EINVAL; 353 err = -EINVAL;
333 if (!dev_name) 354 dev_name_end--; /* back up to ':' separator */
334 goto out; 355 if (*dev_name_end != ':') {
335 *path = strstr(dev_name, ":/"); 356 pr_err("device name is missing path (no : separator in %s)\n",
336 if (*path == NULL) {
337 pr_err("device name is missing path (no :/ in %s)\n",
338 dev_name); 357 dev_name);
339 goto out; 358 goto out;
340 } 359 }
341 dev_name_end = *path;
342 dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name); 360 dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
343
344 /* path on server */
345 *path += 2;
346 dout("server path '%s'\n", *path); 361 dout("server path '%s'\n", *path);
347 362
348 *popt = ceph_parse_options(options, dev_name, dev_name_end, 363 *popt = ceph_parse_options(options, dev_name, dev_name_end,