From nobody Wed Dec 10 20:10:48 2025 Received: from flow-b5-smtp.messagingengine.com (flow-b5-smtp.messagingengine.com [202.12.124.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6EBB71EF36C; Thu, 13 Nov 2025 00:42:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762994536; cv=none; b=RfxM6eMltCuGwsxkpvntII8KT7c/OeQzMZvH+m/ixwtDeW3WW6lZvMkeRGj2zGffjaDFwlIsCMdTx4axwNP3vht0RrWLJQ2CWUTRupiGuAhDlmggUt+XIQNrCARDUPeu+sZ4kW0ot9CTJShxwszqWIjwlH4RgKI8WkMxVEtDokg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762994536; c=relaxed/simple; bh=5TyxKuE95SraoemOmT86ozwF6+e8YnLmLW259EhkVgQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s7epHm/EfUCQLWMbhb+sKv7fcu5zk2KKDkoWTrWgEzVcr1OFTHlr7Skb0LH31aeaPLl6e7KDYxJxFEk99oG8Gg4UT/mVjA7r7bzf5qhikBngQj29gYEpOQ9alZHG+j9Nhkw9QdcFmNd0rg1CKSqg+yyiWmw1dlXy3dR3vdgZyCo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ownmail.net; spf=pass smtp.mailfrom=ownmail.net; dkim=pass (2048-bit key) header.d=ownmail.net header.i=@ownmail.net header.b=AogUmIPh; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=INmI4V5O; arc=none smtp.client-ip=202.12.124.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ownmail.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ownmail.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ownmail.net header.i=@ownmail.net header.b="AogUmIPh"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="INmI4V5O" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailflow.stl.internal (Postfix) with ESMTP id B122413000C2; Wed, 12 Nov 2025 19:42:12 -0500 (EST) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Wed, 12 Nov 2025 19:42:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ownmail.net; h= cc:cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:reply-to:subject:subject:to:to; s=fm3; t=1762994532; x=1763001732; bh=I4wpF9GTqWlVSE87fHNXytUmav0JY1MI0Fk5n2uq6NM=; b= AogUmIPhPf0j6RJUrQ874L6xk8JqME3siWzKRYtNmp7J0gT2bShDBBlA49pCb3Lp lEiEgKTs9NOqpiAjiKQ31bZXOMNjeAs8rXKyPltBNcLQG10hKf38TyWlT69QMZZP Att1oSRwhEv0OK134UDj94UQh+PiRd+M+wVBiygXt5892kAxOFRibXp5aNugBtKu uaQjwNy/FSmSoMd6V0f7rSd6mXP0e5irpdcb8NXJfdEwqEUV/n2hiyYK53/369Km OJVOhI799O6E8cNFN/IyMVg50BDuXbGYjlo6s0WIbpQtFx0TFBEud6Yl/VwFBg5r iFiuMiiNww00jJHDHIPyqQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1762994532; x=1763001732; bh=I 4wpF9GTqWlVSE87fHNXytUmav0JY1MI0Fk5n2uq6NM=; b=INmI4V5OUK7r/Dys/ dNvJEmUJDMEL3CAdGSvNUS66dC7Ft/l6hFaJi9O2lmPPLib441BRBnUfCNyuSzZ9 Ji8PeEEahWqlyVXHj3U8JOKT9+qvzdXD55b5x4Yy3xYsBNPRRAXyvb5yGs+QN8O/ eme+K9qdQaC211vKL5Xub9blr+uJ4rXbVgBA6MiWi6el14+aLEfAIuNxw4cXDRr0 8GuDzDqvXHZETkGCjuOLb30c6W0CurEPm/k8KJ9x2UOW2Kvsq7g6PHFUV0dQH5Hd BAjB9x8Uvfq9Wx2/iKVCvR6JNMB66GkOmXVceiMI5ip39SbdxRHdxMT9JoYOT6vt 7wTEw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggddvtdehheegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhephffvvefufffkofgjfhhrggfgsedtkeertdertddtnecuhfhrohhmpefpvghilheu rhhofihnuceonhgvihhlsgesohifnhhmrghilhdrnhgvtheqnecuggftrfgrthhtvghrnh epveevkeffudeuvefhieeghffgudektdelkeejiedtjedugfeukedvkeffvdefvddunecu vehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepnhgvihhlsg esohifnhhmrghilhdrnhgvthdpnhgspghrtghpthhtohepgedtpdhmohguvgepshhmthhp ohhuthdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpd hrtghpthhtohepshgvlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphht thhopehlihhnuhigqdigfhhssehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoh eplhhinhhugidquhhnihhonhhfshesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphht thhopehlihhnuhigqdhsvggtuhhrihhthidqmhhoughulhgvsehvghgvrhdrkhgvrhhnvg hlrdhorhhgpdhrtghpthhtoheplhhinhhugidqnhhfshesvhhgvghrrdhkvghrnhgvlhdr ohhrghdprhgtphhtthhopehlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhfshguvghvvghlsehvghgvrhdrkhgvrhhn vghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqtghifhhssehvghgvrhdrkhgvrhhnvg hlrdhorhhg X-ME-Proxy: Feedback-ID: iab3e480c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 12 Nov 2025 19:42:01 -0500 (EST) From: NeilBrown To: "Alexander Viro" , "Christian Brauner" , "Amir Goldstein" Cc: "Jan Kara" , linux-fsdevel@vger.kernel.org, Jeff Layton , Chris Mason , David Sterba , David Howells , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Tyler Hicks , Miklos Szeredi , Chuck Lever , Olga Kornievskaia , Dai Ngo , Namjae Jeon , Steve French , Sergey Senozhatsky , Carlos Maiolino , John Johansen , Paul Moore , James Morris , "Serge E. Hallyn" , Stephen Smalley , Ondrej Mosnacek , Mateusz Guzik , Lorenzo Stoakes , Stefan Berger , "Darrick J. Wong" , linux-kernel@vger.kernel.org, netfs@lists.linux.dev, ecryptfs@vger.kernel.org, linux-nfs@vger.kernel.org, linux-unionfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-xfs@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@vger.kernel.org Subject: [PATCH v6 11/15] VFS/ovl/smb: introduce start_renaming_dentry() Date: Thu, 13 Nov 2025 11:18:34 +1100 Message-ID: <20251113002050.676694-12-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20251113002050.676694-1-neilb@ownmail.net> References: <20251113002050.676694-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown Several callers perform a rename on a dentry they already have, and only require lookup for the target name. This includes smb/server and a few different places in overlayfs. start_renaming_dentry() performs the required lookup and takes the required lock using lock_rename_child() It is used in three places in overlayfs and in ksmbd_vfs_rename(). In the ksmbd case, the parent of the source is not important - the source must be renamed from wherever it is. So start_renaming_dentry() allows rd->old_parent to be NULL and only checks it if it is non-NULL. On success rd->old_parent will be the parent of old_dentry with an extra reference taken. Other start_renaming function also now take the extra reference and end_renaming() now drops this reference as well. ovl_lookup_temp(), ovl_parent_lock(), and ovl_parent_unlock() are all removed as they are no longer needed. OVL_TEMPNAME_SIZE and ovl_tempname() are now declared in overlayfs.h so that ovl_check_rename_whiteout() can access them. ovl_copy_up_workdir() now always cleans up on error. Reviewed-by: Namjae Jeon (for ksmbd part) Reviewed-by: Amir Goldstein Reviewed-by: Jeff Layton Signed-off-by: NeilBrown --- fs/namei.c | 108 ++++++++++++++++++++++++++++++++++++--- fs/overlayfs/copy_up.c | 54 +++++++++----------- fs/overlayfs/dir.c | 19 +------ fs/overlayfs/overlayfs.h | 8 +-- fs/overlayfs/super.c | 22 ++++---- fs/overlayfs/util.c | 11 ---- fs/smb/server/vfs.c | 60 ++++------------------ include/linux/namei.h | 2 + 8 files changed, 150 insertions(+), 134 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index bad6c9d540f9..4b740048df97 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3669,7 +3669,7 @@ EXPORT_SYMBOL(unlock_rename); =20 /** * __start_renaming - lookup and lock names for rename - * @rd: rename data containing parent and flags, and + * @rd: rename data containing parents and flags, and * for receiving found dentries * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL, * LOOKUP_NO_SYMLINKS etc). @@ -3680,8 +3680,8 @@ EXPORT_SYMBOL(unlock_rename); * rename. * * On success the found dentries are stored in @rd.old_dentry, - * @rd.new_dentry. These references and the lock are dropped by - * end_renaming(). + * @rd.new_dentry and an extra ref is taken on @rd.old_parent. + * These references and the lock are dropped by end_renaming(). * * The passed in qstrs must have the hash calculated, and no permission * checking is performed. @@ -3735,6 +3735,7 @@ __start_renaming(struct renamedata *rd, int lookup_fl= ags, =20 rd->old_dentry =3D d1; rd->new_dentry =3D d2; + dget(rd->old_parent); return 0; =20 out_dput_d2: @@ -3748,7 +3749,7 @@ __start_renaming(struct renamedata *rd, int lookup_fl= ags, =20 /** * start_renaming - lookup and lock names for rename with permission check= ing - * @rd: rename data containing parent and flags, and + * @rd: rename data containing parents and flags, and * for receiving found dentries * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL, * LOOKUP_NO_SYMLINKS etc). @@ -3759,8 +3760,8 @@ __start_renaming(struct renamedata *rd, int lookup_fl= ags, * rename. * * On success the found dentries are stored in @rd.old_dentry, - * @rd.new_dentry. These references and the lock are dropped by - * end_renaming(). + * @rd.new_dentry. Also the refcount on @rd->old_parent is increased. + * These references and the lock are dropped by end_renaming(). * * The passed in qstrs need not have the hash calculated, and basic * eXecute permission checking is performed against @rd.mnt_idmap. @@ -3782,11 +3783,106 @@ int start_renaming(struct renamedata *rd, int look= up_flags, } EXPORT_SYMBOL(start_renaming); =20 +static int +__start_renaming_dentry(struct renamedata *rd, int lookup_flags, + struct dentry *old_dentry, struct qstr *new_last) +{ + struct dentry *trap; + struct dentry *d2; + int target_flags =3D LOOKUP_RENAME_TARGET | LOOKUP_CREATE; + int err; + + if (rd->flags & RENAME_EXCHANGE) + target_flags =3D 0; + if (rd->flags & RENAME_NOREPLACE) + target_flags |=3D LOOKUP_EXCL; + + /* Already have the dentry - need to be sure to lock the correct parent */ + trap =3D lock_rename_child(old_dentry, rd->new_parent); + if (IS_ERR(trap)) + return PTR_ERR(trap); + if (d_unhashed(old_dentry) || + (rd->old_parent && rd->old_parent !=3D old_dentry->d_parent)) { + /* dentry was removed, or moved and explicit parent requested */ + err =3D -EINVAL; + goto out_unlock; + } + + d2 =3D lookup_one_qstr_excl(new_last, rd->new_parent, + lookup_flags | target_flags); + err =3D PTR_ERR(d2); + if (IS_ERR(d2)) + goto out_unlock; + + if (old_dentry =3D=3D trap) { + /* source is an ancestor of target */ + err =3D -EINVAL; + goto out_dput_d2; + } + + if (d2 =3D=3D trap) { + /* target is an ancestor of source */ + if (rd->flags & RENAME_EXCHANGE) + err =3D -EINVAL; + else + err =3D -ENOTEMPTY; + goto out_dput_d2; + } + + rd->old_dentry =3D dget(old_dentry); + rd->new_dentry =3D d2; + rd->old_parent =3D dget(old_dentry->d_parent); + return 0; + +out_dput_d2: + dput(d2); +out_unlock: + unlock_rename(old_dentry->d_parent, rd->new_parent); + return err; +} + +/** + * start_renaming_dentry - lookup and lock name for rename with permission= checking + * @rd: rename data containing parents and flags, and + * for receiving found dentries + * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL, + * LOOKUP_NO_SYMLINKS etc). + * @old_dentry: dentry of name to move + * @new_last: name of target in @rd.new_parent + * + * Look up target name and ensure locks are in place for + * rename. + * + * On success the found dentry is stored in @rd.new_dentry and + * @rd.old_parent is confirmed to be the parent of @old_dentry. If it + * was originally %NULL, it is set. In either case a reference is taken + * so that end_renaming() can have a stable reference to unlock. + * + * References and the lock can be dropped with end_renaming() + * + * The passed in qstr need not have the hash calculated, and basic + * eXecute permission checking is performed against @rd.mnt_idmap. + * + * Returns: zero or an error. + */ +int start_renaming_dentry(struct renamedata *rd, int lookup_flags, + struct dentry *old_dentry, struct qstr *new_last) +{ + int err; + + err =3D lookup_one_common(rd->mnt_idmap, new_last, rd->new_parent); + if (err) + return err; + return __start_renaming_dentry(rd, lookup_flags, old_dentry, new_last); +} +EXPORT_SYMBOL(start_renaming_dentry); + void end_renaming(struct renamedata *rd) { unlock_rename(rd->old_parent, rd->new_parent); dput(rd->old_dentry); dput(rd->new_dentry); + dput(rd->old_parent); } EXPORT_SYMBOL(end_renaming); =20 diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index e2bdac4317e7..9911a346b477 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -523,8 +523,8 @@ static int ovl_create_index(struct dentry *dentry, cons= t struct ovl_fh *fh, { struct ovl_fs *ofs =3D OVL_FS(dentry->d_sb); struct dentry *indexdir =3D ovl_indexdir(dentry->d_sb); - struct dentry *index =3D NULL; struct dentry *temp =3D NULL; + struct renamedata rd =3D {}; struct qstr name =3D { }; int err; =20 @@ -556,17 +556,15 @@ static int ovl_create_index(struct dentry *dentry, co= nst struct ovl_fh *fh, if (err) goto out; =20 - err =3D ovl_parent_lock(indexdir, temp); + rd.mnt_idmap =3D ovl_upper_mnt_idmap(ofs); + rd.old_parent =3D indexdir; + rd.new_parent =3D indexdir; + err =3D start_renaming_dentry(&rd, 0, temp, &name); if (err) goto out; - index =3D ovl_lookup_upper(ofs, name.name, indexdir, name.len); - if (IS_ERR(index)) { - err =3D PTR_ERR(index); - } else { - err =3D ovl_do_rename(ofs, indexdir, temp, indexdir, index, 0); - dput(index); - } - ovl_parent_unlock(indexdir); + + err =3D ovl_do_rename_rd(&rd); + end_renaming(&rd); out: if (err) ovl_cleanup(ofs, indexdir, temp); @@ -763,7 +761,8 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *= c) struct ovl_fs *ofs =3D OVL_FS(c->dentry->d_sb); struct inode *inode; struct path path =3D { .mnt =3D ovl_upper_mnt(ofs) }; - struct dentry *temp, *upper, *trap; + struct renamedata rd =3D {}; + struct dentry *temp; struct ovl_cu_creds cc; int err; struct ovl_cattr cattr =3D { @@ -807,29 +806,24 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx= *c) * ovl_copy_up_data(), so lock workdir and destdir and make sure that * temp wasn't moved before copy up completion or cleanup. */ - trap =3D lock_rename(c->workdir, c->destdir); - if (trap || temp->d_parent !=3D c->workdir) { - /* temp or workdir moved underneath us? abort without cleanup */ - dput(temp); + rd.mnt_idmap =3D ovl_upper_mnt_idmap(ofs); + rd.old_parent =3D c->workdir; + rd.new_parent =3D c->destdir; + rd.flags =3D 0; + err =3D start_renaming_dentry(&rd, 0, temp, + &QSTR_LEN(c->destname.name, c->destname.len)); + if (err) { + /* temp or workdir moved underneath us? map to -EIO */ err =3D -EIO; - if (!IS_ERR(trap)) - unlock_rename(c->workdir, c->destdir); - goto out; } - - err =3D ovl_copy_up_metadata(c, temp); if (err) - goto cleanup; + goto cleanup_unlocked; =20 - upper =3D ovl_lookup_upper(ofs, c->destname.name, c->destdir, - c->destname.len); - err =3D PTR_ERR(upper); - if (IS_ERR(upper)) - goto cleanup; + err =3D ovl_copy_up_metadata(c, temp); + if (!err) + err =3D ovl_do_rename_rd(&rd); + end_renaming(&rd); =20 - err =3D ovl_do_rename(ofs, c->workdir, temp, c->destdir, upper, 0); - unlock_rename(c->workdir, c->destdir); - dput(upper); if (err) goto cleanup_unlocked; =20 @@ -850,8 +844,6 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *= c) =20 return err; =20 -cleanup: - unlock_rename(c->workdir, c->destdir); cleanup_unlocked: ovl_cleanup(ofs, c->workdir, temp); dput(temp); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index cf6fc48459f3..6b2f88edb497 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -57,8 +57,7 @@ int ovl_cleanup(struct ovl_fs *ofs, struct dentry *workdi= r, return 0; } =20 -#define OVL_TEMPNAME_SIZE 20 -static void ovl_tempname(char name[OVL_TEMPNAME_SIZE]) +void ovl_tempname(char name[OVL_TEMPNAME_SIZE]) { static atomic_t temp_id =3D ATOMIC_INIT(0); =20 @@ -66,22 +65,6 @@ static void ovl_tempname(char name[OVL_TEMPNAME_SIZE]) snprintf(name, OVL_TEMPNAME_SIZE, "#%x", atomic_inc_return(&temp_id)); } =20 -struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir) -{ - struct dentry *temp; - char name[OVL_TEMPNAME_SIZE]; - - ovl_tempname(name); - temp =3D ovl_lookup_upper(ofs, name, workdir, strlen(name)); - if (!IS_ERR(temp) && temp->d_inode) { - pr_err("workdir/%s already exists\n", name); - dput(temp); - temp =3D ERR_PTR(-EIO); - } - - return temp; -} - static struct dentry *ovl_start_creating_temp(struct ovl_fs *ofs, struct dentry *workdir) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 3cc85a893b5c..746bc4ad7b37 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -447,11 +447,6 @@ static inline bool ovl_open_flags_need_copy_up(int fla= gs) } =20 /* util.c */ -int ovl_parent_lock(struct dentry *parent, struct dentry *child); -static inline void ovl_parent_unlock(struct dentry *parent) -{ - inode_unlock(parent->d_inode); -} int ovl_get_write_access(struct dentry *dentry); void ovl_put_write_access(struct dentry *dentry); void ovl_start_write(struct dentry *dentry); @@ -888,7 +883,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent, struct dentry *newdentry, struct ovl_cattr *attr); int ovl_cleanup(struct ovl_fs *ofs, struct dentry *workdir, struct dentry = *dentry); -struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir); +#define OVL_TEMPNAME_SIZE 20 +void ovl_tempname(char name[OVL_TEMPNAME_SIZE]); struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir, struct ovl_cattr *attr); =20 diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 6e0816c1147a..a721ef2b90e8 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -566,9 +566,10 @@ static int ovl_check_rename_whiteout(struct ovl_fs *of= s) { struct dentry *workdir =3D ofs->workdir; struct dentry *temp; - struct dentry *dest; struct dentry *whiteout; struct name_snapshot name; + struct renamedata rd =3D {}; + char name2[OVL_TEMPNAME_SIZE]; int err; =20 temp =3D ovl_create_temp(ofs, workdir, OVL_CATTR(S_IFREG | 0)); @@ -576,23 +577,21 @@ static int ovl_check_rename_whiteout(struct ovl_fs *o= fs) if (IS_ERR(temp)) return err; =20 - err =3D ovl_parent_lock(workdir, temp); + rd.mnt_idmap =3D ovl_upper_mnt_idmap(ofs); + rd.old_parent =3D workdir; + rd.new_parent =3D workdir; + rd.flags =3D RENAME_WHITEOUT; + ovl_tempname(name2); + err =3D start_renaming_dentry(&rd, 0, temp, &QSTR(name2)); if (err) { dput(temp); return err; } - dest =3D ovl_lookup_temp(ofs, workdir); - err =3D PTR_ERR(dest); - if (IS_ERR(dest)) { - dput(temp); - ovl_parent_unlock(workdir); - return err; - } =20 /* Name is inline and stable - using snapshot as a copy helper */ take_dentry_name_snapshot(&name, temp); - err =3D ovl_do_rename(ofs, workdir, temp, workdir, dest, RENAME_WHITEOUT); - ovl_parent_unlock(workdir); + err =3D ovl_do_rename_rd(&rd); + end_renaming(&rd); if (err) { if (err =3D=3D -EINVAL) err =3D 0; @@ -616,7 +615,6 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs) ovl_cleanup(ofs, workdir, temp); release_dentry_name_snapshot(&name); dput(temp); - dput(dest); =20 return err; } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 2da1c035f716..fffc22859211 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1548,14 +1548,3 @@ void ovl_copyattr(struct inode *inode) i_size_write(inode, i_size_read(realinode)); spin_unlock(&inode->i_lock); } - -int ovl_parent_lock(struct dentry *parent, struct dentry *child) -{ - inode_lock_nested(parent->d_inode, I_MUTEX_PARENT); - if (!child || - (!d_unhashed(child) && child->d_parent =3D=3D parent)) - return 0; - - inode_unlock(parent->d_inode); - return -EINVAL; -} diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 148c65d59e42..ea5ab5b0adb1 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -661,7 +661,6 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char = *oldname, int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, char *newname, int flags) { - struct dentry *old_parent, *new_dentry, *trap; struct dentry *old_child =3D old_path->dentry; struct path new_path; struct qstr new_last; @@ -671,7 +670,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const str= uct path *old_path, struct ksmbd_file *parent_fp; int new_type; int err, lookup_flags =3D LOOKUP_NO_SYMLINKS; - int target_lookup_flags =3D LOOKUP_RENAME_TARGET | LOOKUP_CREATE; =20 if (ksmbd_override_fsids(work)) return -ENOMEM; @@ -682,14 +680,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const st= ruct path *old_path, goto revert_fsids; } =20 - /* - * explicitly handle file overwrite case, for compatibility with - * filesystems that may not support rename flags (e.g: fuse) - */ - if (flags & RENAME_NOREPLACE) - target_lookup_flags |=3D LOOKUP_EXCL; - flags &=3D ~(RENAME_NOREPLACE); - retry: err =3D vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH, &new_path, &new_last, &new_type, @@ -706,17 +696,14 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const s= truct path *old_path, if (err) goto out2; =20 - trap =3D lock_rename_child(old_child, new_path.dentry); - if (IS_ERR(trap)) { - err =3D PTR_ERR(trap); + rd.mnt_idmap =3D mnt_idmap(old_path->mnt); + rd.old_parent =3D NULL; + rd.new_parent =3D new_path.dentry; + rd.flags =3D flags; + rd.delegated_inode =3D NULL, + err =3D start_renaming_dentry(&rd, lookup_flags, old_child, &new_last); + if (err) goto out_drop_write; - } - - old_parent =3D dget(old_child->d_parent); - if (d_unhashed(old_child)) { - err =3D -EINVAL; - goto out3; - } =20 parent_fp =3D ksmbd_lookup_fd_inode(old_child->d_parent); if (parent_fp) { @@ -729,44 +716,17 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const s= truct path *old_path, ksmbd_fd_put(work, parent_fp); } =20 - new_dentry =3D lookup_one_qstr_excl(&new_last, new_path.dentry, - lookup_flags | target_lookup_flags); - if (IS_ERR(new_dentry)) { - err =3D PTR_ERR(new_dentry); - goto out3; - } - - if (d_is_symlink(new_dentry)) { + if (d_is_symlink(rd.new_dentry)) { err =3D -EACCES; - goto out4; - } - - if (old_child =3D=3D trap) { - err =3D -EINVAL; - goto out4; - } - - if (new_dentry =3D=3D trap) { - err =3D -ENOTEMPTY; - goto out4; + goto out3; } =20 - rd.mnt_idmap =3D mnt_idmap(old_path->mnt), - rd.old_parent =3D old_parent, - rd.old_dentry =3D old_child, - rd.new_parent =3D new_path.dentry, - rd.new_dentry =3D new_dentry, - rd.flags =3D flags, - rd.delegated_inode =3D NULL, err =3D vfs_rename(&rd); if (err) ksmbd_debug(VFS, "vfs_rename failed err %d\n", err); =20 -out4: - dput(new_dentry); out3: - dput(old_parent); - unlock_rename(old_parent, new_path.dentry); + end_renaming(&rd); out_drop_write: mnt_drop_write(old_path->mnt); out2: diff --git a/include/linux/namei.h b/include/linux/namei.h index 7fdd9fdcbd2b..c47713e9867c 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -159,6 +159,8 @@ extern struct dentry *lock_rename_child(struct dentry *= , struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *); int start_renaming(struct renamedata *rd, int lookup_flags, struct qstr *old_last, struct qstr *new_last); +int start_renaming_dentry(struct renamedata *rd, int lookup_flags, + struct dentry *old_dentry, struct qstr *new_last); void end_renaming(struct renamedata *rd); =20 /** --=20 2.50.0.107.gf914562f5916.dirty