Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp1517230ybb; Sat, 11 Apr 2020 05:27:38 -0700 (PDT) X-Google-Smtp-Source: APiQypKnQI7NMN31VQgt6g40wYRcFQpSMR4XKD1C5FMTfevY90M72REACF+NzWhi3LegjsdkjtmD X-Received: by 2002:a05:620a:228a:: with SMTP id o10mr6426462qkh.457.1586608058570; Sat, 11 Apr 2020 05:27:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1586608058; cv=none; d=google.com; s=arc-20160816; b=gNLvbkwDxMY2w87+0HBxRAlaWGQhzxQBq2rINQ8JwDZCQWPSxUlq9ZCmMhyLgv4Nc1 Wrd7+edJip99U64w3vMyu1mU6hI+83sa9aHHzKkahCOwKRhkl0NW24+HmYp5maDH2HCS ffThEUwoV+zsi74XCGKtqoLSn3sNDfPgSDUyOaM7ZTDxoB1mIue9hU//SaYqHqUHkRed G9jvxLDdqD/kCoZMC8XPAldMEjL97tQiQPmThheapmimP0FVpZ9evrqhjt7WNTJMrr2/ f9PuIK0Ow2lQshRjuDDrmgVaC3Ic8ZXm2K9Xt5mxIC8Ee5E7eXQYVXeJu8cFtkJ2LmEv cGRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=sLZk7Xu5aqKorFUOioLP+ZR+k2FbCganv+GnazjkFMg=; b=ncyDvapyryI+8KNKOtFrXQjbCUEGbZS7cglBIv1g2xg0qL+gmUhMjDr5tst5PaiKl5 80nU2bZll2faVJkuNepr66ABpf6S1uxi87LTFUm1laufuaOXtx5+VezJlMfElmRX/g0O puqOVijf+0kpqBLv9MFmB1jwyHOd0jmjiBjO9nwoHFxdkU/oqfI3OFdoGA6CgMET37gB YlDWn+u1+z0lwuUvhLR6s9dUphXXmqvvlbKwyuvQG6uzVlzHgmlSJmU7JZsN/ClkjEqo bq8AZ1s5jywXorrChxTuzyJuLTowLkak926hCct9C9BDV3knOSTheSTg5YlGmz7/gB5q BV5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=vZqA1N9q; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l16si2496061qvl.193.2020.04.11.05.27.24; Sat, 11 Apr 2020 05:27:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=vZqA1N9q; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728221AbgDKMQJ (ORCPT + 99 others); Sat, 11 Apr 2020 08:16:09 -0400 Received: from mail.kernel.org ([198.145.29.99]:50174 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728230AbgDKMQB (ORCPT ); Sat, 11 Apr 2020 08:16:01 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id E96D42137B; Sat, 11 Apr 2020 12:16:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1586607361; bh=p2fC9a56OyY2NX7S5FDk/W4b4PD9LKA+2g1VNT1Dh6Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vZqA1N9q3TKoYFq8CeFQHkzsBSPJpNSvaZrpIfWDhtQWCIC8PPXkdSjYyxR6ClFTw H56ZBrqG7OBIx6GbfjPBiToIyaZ2ItoImYfMMP1UloDS90eVaPT2YUsc2wQpDAVMjT X2SPURqAPpwjrESCkTD59qu5nnu7iweTBpYnA23U= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Xiubo Li , Jeff Layton , Ilya Dryomov , Luis Henriques Subject: [PATCH 4.19 42/54] ceph: remove the extra slashes in the server path Date: Sat, 11 Apr 2020 14:09:24 +0200 Message-Id: <20200411115512.797075966@linuxfoundation.org> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200411115508.284500414@linuxfoundation.org> References: <20200411115508.284500414@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Xiubo Li commit 4fbc0c711b2464ee1551850b85002faae0b775d5 upstream. It's possible to pass the mount helper a server path that has more than one contiguous slash character. For example: $ mount -t ceph 192.168.195.165:40176:/// /mnt/cephfs/ In the MDS server side the extra slashes of the server path will be treated as snap dir, and then we can get the following debug logs: ceph: mount opening path // ceph: open_root_inode opening '//' ceph: fill_trace 0000000059b8a3bc is_dentry 0 is_target 1 ceph: alloc_inode 00000000dc4ca00b ceph: get_inode created new inode 00000000dc4ca00b 1.ffffffffffffffff ino 1 ceph: get_inode on 1=1.ffffffffffffffff got 00000000dc4ca00b And then when creating any new file or directory under the mount point, we can hit the following BUG_ON in ceph_fill_trace(): BUG_ON(ceph_snap(dir) != dvino.snap); Have the client ignore the extra slashes in the server path when mounting. This will also canonicalize the path, so that identical mounts can be consilidated. 1) "//mydir1///mydir//" 2) "/mydir1/mydir" 3) "/mydir1/mydir/" Regardless of the internal treatment of these paths, the kernel still stores the original string including the leading '/' for presentation to userland. URL: https://tracker.ceph.com/issues/42771 Signed-off-by: Xiubo Li Reviewed-by: Jeff Layton Signed-off-by: Ilya Dryomov Signed-off-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman --- fs/ceph/super.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 19 deletions(-) --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -105,7 +105,6 @@ static int ceph_statfs(struct dentry *de return 0; } - static int ceph_sync_fs(struct super_block *sb, int wait) { struct ceph_fs_client *fsc = ceph_sb_to_client(sb); @@ -399,6 +398,73 @@ static int strcmp_null(const char *s1, c return strcmp(s1, s2); } +/** + * path_remove_extra_slash - Remove the extra slashes in the server path + * @server_path: the server path and could be NULL + * + * Return NULL if the path is NULL or only consists of "/", or a string + * without any extra slashes including the leading slash(es) and the + * slash(es) at the end of the server path, such as: + * "//dir1////dir2///" --> "dir1/dir2" + */ +static char *path_remove_extra_slash(const char *server_path) +{ + const char *path = server_path; + const char *cur, *end; + char *buf, *p; + int len; + + /* if the server path is omitted */ + if (!path) + return NULL; + + /* remove all the leading slashes */ + while (*path == '/') + path++; + + /* if the server path only consists of slashes */ + if (*path == '\0') + return NULL; + + len = strlen(path); + + buf = kmalloc(len + 1, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + end = path + len; + p = buf; + do { + cur = strchr(path, '/'); + if (!cur) + cur = end; + + len = cur - path; + + /* including one '/' */ + if (cur != end) + len += 1; + + memcpy(p, path, len); + p += len; + + while (cur <= end && *cur == '/') + cur++; + path = cur; + } while (path < end); + + *p = '\0'; + + /* + * remove the last slash if there has and just to make sure that + * we will get something like "dir1/dir2" + */ + if (*(--p) == '/') + *p = '\0'; + + return buf; +} + static int compare_mount_options(struct ceph_mount_options *new_fsopt, struct ceph_options *new_opt, struct ceph_fs_client *fsc) @@ -406,6 +472,7 @@ static int compare_mount_options(struct 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); @@ -418,9 +485,21 @@ static int compare_mount_options(struct 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; @@ -476,12 +555,14 @@ static int parse_mount_options(struct ce */ 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; - } + /* + * The server_path will include the whole chars from userland + * including the leading '/'. + */ + 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); @@ -810,7 +891,6 @@ static void destroy_caches(void) ceph_fscache_unregister(); } - /* * ceph_umount_begin - initiate forced umount. Tear down down the * mount, skipping steps that may hang while waiting for server(s). @@ -897,9 +977,6 @@ out: return root; } - - - /* * mount: join the ceph cluster, and open root directory. */ @@ -913,7 +990,7 @@ static struct dentry *ceph_real_mount(st 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; @@ -925,19 +1002,24 @@ static struct dentry *ceph_real_mount(st goto out; } - if (!fsc->mount_options->server_path) { - path = ""; - dout("mount opening path \\t\n"); - } else { - path = fsc->mount_options->server_path + 1; - dout("mount opening path %s\n", 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 or just consists of '/' */ + if (!p) + path = ""; + else + path = p; + dout("mount opening path '%s'\n", path); err = ceph_fs_debugfs_init(fsc); if (err < 0) goto out; root = open_root_dentry(fsc, path, started); + kfree(p); if (IS_ERR(root)) { err = PTR_ERR(root); goto out;