[RFC] ceph: remove the extra slashes in the server path
diff mbox series

Message ID 20191114024019.25417-1-xiubli@redhat.com
State New
Headers show
Series
  • [RFC] ceph: remove the extra slashes in the server path
Related show

Commit Message

Xiubo Li Nov. 14, 2019, 2:40 a.m. UTC
From: Xiubo Li <xiubli@redhat.com>

When mounting if the server path has more than one slash, such as:

'mount.ceph 192.168.195.165:40176:/// /mnt/cephfs/'

In the MDS server side the extra slash will be treated as snap dir,
and then we can get the following debug logs:

<7>[  ...] ceph:  mount opening path //
<7>[  ...] ceph:  open_root_inode opening '//'
<7>[  ...] ceph:  fill_trace 0000000059b8a3bc is_dentry 0 is_target 1
<7>[  ...] ceph:  alloc_inode 00000000dc4ca00b
<7>[  ...] ceph:  get_inode created new inode 00000000dc4ca00b 1.ffffffffffffffff ino 1
<7>[  ...] ceph:  get_inode on 1=1.ffffffffffffffff got 00000000dc4ca00b

And then when creating any new file or directory under the mount
point, we can get the following crash core dump:

<4>[  ...] ------------[ cut here ]------------
<2>[  ...] kernel BUG at fs/ceph/inode.c:1347!
<4>[  ...] invalid opcode: 0000 [#1] SMP PTI
<4>[  ...] CPU: 0 PID: 7 Comm: kworker/0:1 Tainted: G            E     5.4.0-rc5+ #1
<4>[  ...] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/19/2017
<4>[  ...] Workqueue: ceph-msgr ceph_con_workfn [libceph]
<4>[  ...] RIP: 0010:ceph_fill_trace+0x992/0xb30 [ceph]
<4>[  ...] Code: ff 0f 0b 0f 0b 0f 0b 4c 89 fa 48 c7 c6 4d [...]
<4>[  ...] RSP: 0018:ffffa23d40067c70 EFLAGS: 00010297
<4>[  ...] RAX: fffffffffffffffe RBX: ffff8a229eb566c0 RCX: 0000000000000006
<4>[  ...] RDX: 0000000000000000 RSI: 0000000000000092 RDI: ffff8a23aec17900
<4>[  ...] RBP: ffff8a226bd91eb0 R08: 0000000000000001 R09: 0000000000000885
<4>[  ...] R10: 000000000002dfd8 R11: ffff8a226bd95b30 R12: ffff8a239347e000
<4>[  ...] R13: 0000000000000000 R14: ffff8a22fabeb000 R15: ffff8a2338b0c900
<4>[  ...] FS:  0000000000000000(0000) GS:ffff8a23aec00000(0000) knlGS:0000000000000000
<4>[  ...] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[  ...] CR2: 000055b479d92068 CR3: 00000003764f6004 CR4: 00000000003606f0
<4>[  ...] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
<4>[  ...] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
<4>[  ...] Call Trace:
<4>[  ...]  dispatch+0x2ac/0x12b0 [ceph]
<4>[  ...]  ceph_con_workfn+0xd40/0x27c0 [libceph]
<4>[  ...]  process_one_work+0x1b0/0x350
<4>[  ...]  worker_thread+0x50/0x3b0
<4>[  ...]  kthread+0xfb/0x130
<4>[  ...]  ? process_one_work+0x350/0x350
<4>[  ...]  ? kthread_park+0x90/0x90
<4>[  ...]  ret_from_fork+0x35/0x40
<4>[  ...] Modules linked in: ceph(E) libceph fscache [...]
<4>[  ...] ---[ end trace ba883d8ccf9afcb0 ]---
<4>[  ...] RIP: 0010:ceph_fill_trace+0x992/0xb30 [ceph]
<4>[  ...] Code: ff 0f 0b 0f 0b 0f 0b 4c 89 fa 48 c7 c6 [...]
<4>[  ...] RSP: 0018:ffffa23d40067c70 EFLAGS: 00010297
<4>[  ...] RAX: fffffffffffffffe RBX: ffff8a229eb566c0 RCX: 0000000000000006
<4>[  ...] RDX: 0000000000000000 RSI: 0000000000000092 RDI: ffff8a23aec17900
<4>[  ...] RBP: ffff8a226bd91eb0 R08: 0000000000000001 R09: 0000000000000885
<4>[  ...] R10: 000000000002dfd8 R11: ffff8a226bd95b30 R12: ffff8a239347e000
<4>[  ...] R13: 0000000000000000 R14: ffff8a22fabeb000 R15: ffff8a2338b0c900
<4>[  ...] FS:  0000000000000000(0000) GS:ffff8a23aec00000(0000) knlGS:0000000000000000
<4>[  ...] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[  ...] CR2: 000055b479d92068 CR3: 00000003764f6004 CR4: 00000000003606f0
<4>[  ...] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
<4>[  ...] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400

And we should ignore the extra slashes in the server path when mount
opening in case users have added them by mistake:

"//mydir1///mydir//" --> "mydir1/mydir/"

Signed-off-by: Xiubo Li <xiubli@redhat.com>
---
 fs/ceph/super.c | 71 ++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 61 insertions(+), 10 deletions(-)

Patch
diff mbox series

diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index b47f43fc2d68..91985c53e611 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -430,6 +430,39 @@  static int strcmp_null(const char *s1, const char *s2)
 	return strcmp(s1, s2);
 }
 
+static char *path_remove_extra_slash(const char *path)
+{
+	bool last_is_slash;
+	int i, j;
+	int len;
+	char *p;
+
+	if (!path)
+		return NULL;
+
+	len = strlen(path);
+
+	p = kmalloc(len, GFP_NOFS);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	last_is_slash = false;
+	for (j = 0, i = 0; i < len; i++) {
+		if (path[i] == '/') {
+			if (last_is_slash)
+				continue;
+			last_is_slash = true;
+		} else {
+			last_is_slash = false;
+		}
+		p[j++] = path[i];
+	}
+
+	p[j] = '\0';
+
+	return p;
+}
+
 static int compare_mount_options(struct ceph_mount_options *new_fsopt,
 				 struct ceph_options *new_opt,
 				 struct ceph_fs_client *fsc)
@@ -437,6 +470,7 @@  static int compare_mount_options(struct ceph_mount_options *new_fsopt,
 	struct ceph_mount_options *fsopt1 = new_fsopt;
 	struct ceph_mount_options *fsopt2 = fsc->mount_options;
 	int ofs = offsetof(struct ceph_mount_options, snapdir_name);
+	char *p1, *p2;
 	int ret;
 
 	ret = memcmp(fsopt1, fsopt2, ofs);
@@ -449,9 +483,21 @@  static int compare_mount_options(struct ceph_mount_options *new_fsopt,
 	ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
 	if (ret)
 		return ret;
-	ret = strcmp_null(fsopt1->server_path, fsopt2->server_path);
+
+	p1 = path_remove_extra_slash(fsopt1->server_path);
+	if (IS_ERR(p1))
+		return PTR_ERR(p1);
+	p2 = path_remove_extra_slash(fsopt2->server_path);
+	if (IS_ERR(p2)) {
+		kfree(p1);
+		return PTR_ERR(p2);
+	}
+	ret = strcmp_null(p1, p2);
+	kfree(p1);
+	kfree(p2);
 	if (ret)
 		return ret;
+
 	ret = strcmp_null(fsopt1->fscache_uniq, fsopt2->fscache_uniq);
 	if (ret)
 		return ret;
@@ -507,12 +553,10 @@  static int parse_mount_options(struct ceph_mount_options **pfsopt,
 	 */
 	dev_name_end = strchr(dev_name, '/');
 	if (dev_name_end) {
-		if (strlen(dev_name_end) > 1) {
-			fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
-			if (!fsopt->server_path) {
-				err = -ENOMEM;
-				goto out;
-			}
+		fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
+		if (!fsopt->server_path) {
+			err = -ENOMEM;
+			goto out;
 		}
 	} else {
 		dev_name_end = dev_name + strlen(dev_name);
@@ -945,7 +989,7 @@  static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
 	mutex_lock(&fsc->client->mount_mutex);
 
 	if (!fsc->sb->s_root) {
-		const char *path;
+		const char *path, *p;
 		err = __ceph_open_session(fsc->client, started);
 		if (err < 0)
 			goto out;
@@ -957,17 +1001,24 @@  static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
 				goto out;
 		}
 
-		if (!fsc->mount_options->server_path) {
+		p = path_remove_extra_slash(fsc->mount_options->server_path);
+		if (IS_ERR(p)) {
+			err = PTR_ERR(p);
+			goto out;
+		}
+		/* if the server path is omitted in the dev_name or just '/' */
+		if (!p || (p && strlen(p) == 1)) {
 			path = "";
 			dout("mount opening path \\t\n");
 		} else {
-			path = fsc->mount_options->server_path + 1;
+			path = p + 1;
 			dout("mount opening path %s\n", path);
 		}
 
 		ceph_fs_debugfs_init(fsc);
 
 		root = open_root_dentry(fsc, path, started);
+		kfree(p);
 		if (IS_ERR(root)) {
 			err = PTR_ERR(root);
 			goto out;