From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 2E2A0343D7B for ; Mon, 13 Jul 2026 06:22:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783923767; cv=none; b=Iyct37GgeGwLqiM7htOHbIaUlxl2X035jvQMMFyeEn4yhOCEFNxm9s0kdiCZnVajCsTlJceXnSVBW7OQ6/l5ztRTUw7Wz9aLjR8YneDxMZ/6nvL56KBBzVJBPHQ5XqISH3NCfzAt4HwyMWJZ9eRqggrpkl70Ji/s01Ix//hY+RM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783923767; c=relaxed/simple; bh=3ojYj3N9aRqg73lQVAOhrKrYM4B0Kb7/o9DjLbymwPE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K3GaNrfnRlYEhQl0Wjv6Nngi9SZurGrgkpWSwCxAetmNJpNzyZpjgOBGiettbnCmWFb/fM9U3BhThTG+bPIOUgwEpCM1Qdj9y8Ezq6PDmf7FJEdlgxtWl6pBYj4tApK6MKWU7dtoSSRWrKcrqluXA+0tXH37NWhZZ17oiV84Q2g= 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=dPLVsckj; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=OD2S4ksX; arc=none smtp.client-ip=202.12.124.148 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="dPLVsckj"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="OD2S4ksX" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 6A8EE1D00051; Mon, 13 Jul 2026 02:22:45 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Mon, 13 Jul 2026 02:22:45 -0400 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=fm2; t=1783923765; x=1784010165; bh=bBH70xF6zLz1o4h3l/SjNmcIsJ+Sn6O8RvRWwvhw1Fs=; b= dPLVsckj0hDr0Sf6YArVQ42L+GfIo4PXbYaBFGxjNQVOxjSGCpQoaVP7fiZ0wCJ+ aQ0XC0NTw4JHISomrWV3cxLx3jWyljRnmMkZEWhYsyv6kyfrkn3AFJMKKAfsJPop 07AgWvDS98w32KNpExjtBXEKgm9875bSjLR+y6hPpo7yQvXH3a/SOFddUF4603sp EsuKcCEgIOtZc+zVPGO1UYTnm2DJQkUZI1z8jTC2HNzUebFaDB+CUeNnHAok+df1 sSG65pyQnq09ZW1IVgn7EVX3XKcg7uOV0lNnoQ/2an8wGKJ6uRsvFztSmzMxrClk X7FQFLkHgNRMRqMVOtDDkA== 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=fm2; t=1783923765; x=1784010165; bh=b BH70xF6zLz1o4h3l/SjNmcIsJ+Sn6O8RvRWwvhw1Fs=; b=OD2S4ksX6I66w+uGG iMoVTs8GcEFRpVcGwi9akFqDem9/Y9VikLdEbQQ3BbWk2IVoAkj9tFYfyGDXH2h7 Z181uvwSLutg+2YdNJAVBc/hSlmXX7vWw7h/pJTRi0BNcLCqsGq2ZzAtgAd9aEAh IXiFMXMx5ZK79n9ZTp+GfN6YVjXySSx6xPw+hOGgOuBGWyeqV0gW5Om7V7l4USRS HwypN2vzDrtyNXn5f4+bTosQHgCtTPpaTnAogPlJ7wMCw/r4SFEFFCC68fJcwVXd 5o0vPQt5WOI/ZpbsB3cwE5O5/yVaSo9GabdHw3GiKK3vj99ujWkuuGNLXfZBOAMP PIMsw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGCQLlV7rkBD/d/I31+FnWtoJqihf/xdHHsD1TT1SXgkZmv6s4HWqyOhFnVY9n5MU BOJtfUQyVpUKpBykWA7VcVygcWfF57rWMRxVOWH1WLSaRWqIdVkOkFztYwGNBEJqYCGdER lIjYSwxT52xjXFVZpJf8rJpvaK2n+rZveXXBjrP8wYzN/FLD3xS33T1EHtom553cqC8fjn PrLIVOrVJtl+mjvVoS1EqhD6Dvk80GmCtdpbSpYdhpfrTqNe15e9hEbxs6wUV0rVyj4+GV nLsskUnL0p4PWJePiP27X7oGhT/Dg2xDgvflUJ5tmToCi4jiK9SzoT7k7idnqqIq2oUzq0 /YAAh0WupD6eB48W0eOrsFE/4pFKpEv+WZelz1n2oLPbrTIVpt5xq3wXBW9sKQIUkOn9aT PHH2BRzZf0kCAlmMpQq/2yxjqFlleprEgA/ZEVXLm8PKR40Nnrp78QSav+mlDVsmGIjyIC tjAf7juOZvkE1YJvsLABFqOnmsOujvt+X0z5NG09DA5lWvxJVBqfwF//lveLBXpq3MUqmT ZTC9q149SHYjJZKfgZwF9j3Wek0x2twV18Yrh3/SCmPWmVPUopqsgb4aVZhqaaCG71UF56 /sPhBP0pt+R262kHv1jfnHSv1hpVekDwWnZUJ+gUuSxEgf9yoSrWLnP1CHKg X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 13 Jul 2026 02:22:43 -0400 (EDT) From: NeilBrown To: Chuck Lever , Jeff Layton Cc: Olga Kornievskaia , Dai Ngo , Tom Talpey , linux-nfs@vger.kernel.org Subject: [PATCH v3 02/17] nfsd: correctly handle CREATE of mounted-on files Date: Mon, 13 Jul 2026 16:15:25 +1000 Message-ID: <20260713062219.6399-3-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260713062219.6399-1-neilb@ownmail.net> References: <20260713062219.6399-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: NeilBrown Linux allows a file (non-directory) to be mounted on a file. nfsd mostly supports this if the crossmnt option is in effect. However if CREATE is used on an existing mounted-on file, the filehandle for the underlying file is returns. The client will then continue to use that filehandle. So cat /mnt/file will show the contents of the mounted file as expected, but if the dcache is flushed with "drop_caches" or similar, then >> /mnt/file cat /mnt/file will show the mounted-on file. For exclusive or checked creates this is not a problem as the creation will fail no matter which file is seen. For unchecked creates we need to see if the name is in the dcache, and if it is mounted. If so, we simply provide that filehandle, possibly truncating. Signed-off-by: NeilBrown --- fs/nfsd/nfs3proc.c | 28 ++++++++++++++++++++++++++++ fs/nfsd/nfs4proc.c | 30 ++++++++++++++++++++++++++++++ fs/nfsd/nfsproc.c | 24 +++++++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index bbaef884f893..20eaf56fa9e7 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -303,6 +303,34 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, parent = fhp->fh_dentry; inode = d_inode(parent); + if (argp->createmode == NFS3_CREATE_UNCHECKED) { + /* + * If name is already in dcache we need to check for mountpoints + */ + child = try_lookup_noperm(&QSTR_LEN(argp->name, + argp->len), + parent); + if (child && !IS_ERR(child) && d_is_reg(child) && + unlikely(nfsd_mountpoint(child, fhp->fh_export))) { + struct svc_export *exp = exp_get(fhp->fh_export); + if (nfsd_cross_mnt(rqstp, &child, &exp) == 0) { + status = check_nfsd_access(exp, rqstp, false); + if (status == nfs_ok) + status = fh_compose(resfhp, exp, + child, fhp); + if (status == nfs_ok) + status = nfsd_create_setattr( + rqstp, fhp, resfhp, &attrs); + dput(child); + exp_put(exp); + return status; + } + exp_put(exp); + } + if (!IS_ERR(child)) + dput(child); + } + host_err = fh_want_write(fhp); if (host_err) return nfserrno(host_err); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ca9460e97e2b..9a8c1e37cc0f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -270,6 +270,36 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, parent = fhp->fh_dentry; inode = d_inode(parent); + if (open->op_createmode == NFS4_CREATE_UNCHECKED) { + /* + * If name is already in dcache we need to check for mountpoints + */ + child = try_lookup_noperm(&QSTR_LEN(open->op_fname, + open->op_fnamelen), + parent); + if (child && !IS_ERR(child) && d_is_reg(child) && + unlikely(nfsd_mountpoint(child, fhp->fh_export))) { + struct svc_export *exp = exp_get(fhp->fh_export); + if (nfsd_cross_mnt(rqstp, &child, &exp) == 0) { + status = check_nfsd_access(exp, rqstp, false); + if (status == nfs_ok) + status = fh_compose(resfhp, exp, + child, fhp); + if (status == nfs_ok) + status = fh_fill_both_attrs(fhp); + open->op_truncate = + (iap->ia_valid & ATTR_SIZE) && + !iap->ia_size; + dput(child); + exp_put(exp); + return status; + } + exp_put(exp); + } + if (!IS_ERR(child)) + dput(child); + } + host_err = fh_want_write(fhp); if (host_err) return nfserrno(host_err); diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index f60043632575..549eed8f2c19 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -302,11 +302,34 @@ nfsd_proc_create(struct svc_rqst *rqstp) if (resp->status != nfs_ok) goto done; /* must fh_put dirfhp even on error */ + fh_init(newfhp, NFS_FHSIZE); + /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ resp->status = nfserr_exist; if (name_is_dot_dotdot(argp->name, argp->len)) goto done; + + /* + * If name is already in dcache we need to check for mountpoints + */ + dchild = try_lookup_noperm(&QSTR_LEN(argp->name, argp->len), + dirfhp->fh_export); + if (dchild && !IS_ERR(dchild) && d_is_reg(child) && + unlikely(nfsd_mountpoint(dchild, fhp->fh_export))) { + struct svc_export *exp = fhp->fh_export; + if (nfsd_cross_mnt(rqstp, &dchild, &exp) == 0 && + d_isreg(dchild)) { + resp->status = check_nfsd_access(exp, rqstp, false); + if (resp->status == nfs_ok) + resp->status = fh_compose(newfhp, dirfhp->fh_export, + dchild, dirfhp); + goto done; + } + } + if (!IS_ERR(dchild)) + dput(dchild); + hosterr = fh_want_write(dirfhp); if (hosterr) { resp->status = nfserrno(hosterr); @@ -319,7 +342,6 @@ nfsd_proc_create(struct svc_rqst *rqstp) resp->status = nfserrno(PTR_ERR(dchild)); goto out_write; } - fh_init(newfhp, NFS_FHSIZE); resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); if (!resp->status && d_really_is_negative(dchild)) resp->status = nfserr_noent; -- 2.50.0.107.gf914562f5916.dirty