diff mbox series

[6/6] nfsd: add nfsd_file_acquire_local().

Message ID 20240701025802.22985-7-neilb@suse.de (mailing list archive)
State New
Headers show
Series nfsd: provide simpler interface for LOCALIO access | expand

Commit Message

NeilBrown July 1, 2024, 2:53 a.m. UTC
nfsd_file_acquire_local() can be used to look up a file by filehandle
without having a struct rqst.  This can be used by NFS LOCALIO to allow
the NFS client to by the NFS protocol to directly access a file provided
by the NFS server which is running in the same kernel.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 fs/nfsd/filecache.c | 54 ++++++++++++++++++++++++++++++++++++++++-----
 fs/nfsd/filecache.h |  4 ++++
 fs/nfsd/nfsfh.c     |  2 +-
 fs/nfsd/nfsfh.h     |  5 +++++
 4 files changed, 59 insertions(+), 6 deletions(-)

Comments

Jeff Layton July 1, 2024, 11:21 a.m. UTC | #1
On Mon, 2024-07-01 at 12:53 +1000, NeilBrown wrote:
> nfsd_file_acquire_local() can be used to look up a file by filehandle
> without having a struct rqst.  This can be used by NFS LOCALIO to allow
> the NFS client to by the NFS protocol to directly access a file provided
> by the NFS server which is running in the same kernel.
> 
> Signed-off-by: NeilBrown <neilb@suse.de>
> ---
>  fs/nfsd/filecache.c | 54 ++++++++++++++++++++++++++++++++++++++++-----
>  fs/nfsd/filecache.h |  4 ++++
>  fs/nfsd/nfsfh.c     |  2 +-
>  fs/nfsd/nfsfh.h     |  5 +++++
>  4 files changed, 59 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
> index ad9083ca144b..87f965d2574b 100644
> --- a/fs/nfsd/filecache.c
> +++ b/fs/nfsd/filecache.c
> @@ -977,7 +977,10 @@ nfsd_file_is_cached(struct inode *inode)
>  }
>  
>  static __be32
> -nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
> +nfsd_file_do_acquire(struct svc_rqst *rqstp, struct nfsd_net *nn,
> +		     struct svc_cred *cred, int nfs_vers,
> +		     struct auth_domain *client,
> +		     struct svc_fh *fhp,
>  		     unsigned int may_flags, struct file *file,
>  		     struct nfsd_file **pnf, bool want_gc)
>  {
> @@ -991,7 +994,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  	int ret;
>  
>  retry:
> -	status = fh_verify(rqstp, fhp, S_IFREG,
> +	status = __fh_verify(rqstp, nn, cred, nfs_vers, client, fhp, S_IFREG,
>  				may_flags|NFSD_MAY_OWNER_OVERRIDE);
>  	if (status != nfs_ok)
>  		return status;
> @@ -1139,7 +1142,8 @@ __be32
>  nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		     unsigned int may_flags, struct nfsd_file **pnf)
>  {
> -	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
> +	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL,
> +				    fhp, may_flags, NULL, pnf, true);
>  }
>  
>  /**
> @@ -1163,7 +1167,46 @@ __be32
>  nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		  unsigned int may_flags, struct nfsd_file **pnf)
>  {
> -	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
> +	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL, fhp,
> +				    may_flags, NULL, pnf, false);
> +}
> +
> +/**
> + * nfsd_file_acquire_local - Get a struct nfsd_file with an open file for localio
> + * @nn: The nfsd network namespace in which to perform a lookup
> + * @cred: the user credential with which to validate access
> + * @nfs_vers: NFS version number to assume for request
> + * @client: the auth_domain for LOCALIO lookup
> + * @fhp: the NFS filehandle of the file to be opened
> + * @may_flags: NFSD_MAY_ settings for the file
> + * @pnf: OUT: new or found "struct nfsd_file" object
> + *
> + * This file lookup interface provide access to a file given the
> + * filehandle and credential.  No connection-based authorisation
> + * is performed and in that way it is quite different to other
> + * file access mediated by nfsd.  It allows a kernel module such as the NFS
> + * client to reach across network and filesystem namespaces to access
> + * a file.  The security implications of this should be carefully
> + * considered before use.
> + *
> + * The nfsd_file_object returned by this API is reference-counted
> + * but not garbage-collected. The object is unhashed after the
> + * final nfsd_file_put().
> + *
> + * Return values:
> + *   %nfs_ok - @pnf points to an nfsd_file with its reference
> + *   count boosted.
> + *
> + * On error, an nfsstat value in network byte order is returned.
> + */
> +__be32
> +nfsd_file_acquire_local(struct nfsd_net *nn, struct svc_cred *cred,
> +			int nfs_vers, struct auth_domain *client,
> +			struct svc_fh *fhp,
> +			unsigned int may_flags, struct nfsd_file **pnf)
> +{
> +	return nfsd_file_do_acquire(NULL, nn, cred, nfs_vers, client,
> +				    fhp, may_flags, NULL, pnf, false);

It still seems to me like these should be garbage-collected.

Neil, in an earlier email you mentioned that the client could hold onto
the nfsd_file reference over several operations and then put it. That
would be fine too, but I'm unclear on how the client will manage this.
Does the client have a way to keep track of the nfsd_file over several
operations to the same inode?

Even then, I still think we're probably better off just garbage
collecting thse, since it seems likely that they will end up being
reused in many cases.

>  }
>  
>  /**
> @@ -1189,7 +1232,8 @@ nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  			 unsigned int may_flags, struct file *file,
>  			 struct nfsd_file **pnf)
>  {
> -	return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
> +	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL,
> +				    fhp, may_flags, file, pnf, false);
>  }
>  
>  /*
> diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
> index c61884def906..d179dbae98e3 100644
> --- a/fs/nfsd/filecache.h
> +++ b/fs/nfsd/filecache.h
> @@ -65,5 +65,9 @@ __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  __be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		  unsigned int may_flags, struct file *file,
>  		  struct nfsd_file **nfp);
> +__be32 nfsd_file_acquire_local(struct nfsd_net *nn, struct svc_cred *cred,
> +			       int nfs_vers, struct auth_domain *client,
> +			       struct svc_fh *fhp,
> +			       unsigned int may_flags, struct nfsd_file **pnf);
>  int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
>  #endif /* _FS_NFSD_FILECACHE_H */
> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> index fb5a23060a4c..fa7e358d91ab 100644
> --- a/fs/nfsd/nfsfh.c
> +++ b/fs/nfsd/nfsfh.c
> @@ -328,7 +328,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn,
>   * @access is formed from the NFSD_MAY_* constants defined in
>   * fs/nfsd/vfs.h.
>   */
> -static __be32
> +__be32
>  __fh_verify(struct svc_rqst *rqstp,
>  	    struct nfsd_net *nn, struct svc_cred *cred,
>  	    int nfs_vers, struct auth_domain *client,
> diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> index 6ebdf7ea27bf..a2d9962f1bf8 100644
> --- a/fs/nfsd/nfsfh.h
> +++ b/fs/nfsd/nfsfh.h
> @@ -214,7 +214,12 @@ extern char * SVCFH_fmt(struct svc_fh *fhp);
>  /*
>   * Function prototypes
>   */
> +struct nfsd_net;
>  __be32	fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
> +__be32	__fh_verify(struct svc_rqst *rqstp,
> +		    struct nfsd_net *nn, struct svc_cred *cred,
> +		    int nfs_vers, struct auth_domain *client,
> +		    struct svc_fh *fhp, umode_t type, int access);
>  __be32	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
>  __be32	fh_update(struct svc_fh *);
>  void	fh_put(struct svc_fh *);
NeilBrown July 1, 2024, 11:55 p.m. UTC | #2
On Mon, 01 Jul 2024, Jeff Layton wrote:
> 
> Neil, in an earlier email you mentioned that the client could hold onto
> the nfsd_file reference over several operations and then put it. That
> would be fine too, but I'm unclear on how the client will manage this.
> Does the client have a way to keep track of the nfsd_file over several
> operations to the same inode?

Looking at 
   [PATCH v10 13/19] nfs: add "localio" support

you can see that 
   struct file *local_filp;
is added to "struct nfs_open_context".  An nfs_open_context is stored
in file->private_data and is attached to the inode via nfsi->open_files.
It holds the nfs state for any file open on the NFS filesystem..

->local_filp is set the first time nfs_local_file_open_cache() is called
and remains set until the final __put_nfs_open_context() call destroys
the context.  So it lasts as long as the NFS file is open.  Note that
only one successful ->nfsd_open_local_fh() call is made for each opened
NFS file.  All IO then uses the "struct file*" with no further reference
to nfsd.

If we stored an nfsd_file in the nfs_open_context, either as well as
the 'struct file*' or instead of, then we could call nfsd_file_put()
when the nfs file is closed.  That seems to be the correct lifetime and
matches (almost) exactly what happens with NFSv4 where OPEN and CLOSE
are send over the wire.

> 
> Even then, I still think we're probably better off just garbage
> collecting thse, since it seems likely that they will end up being
> reused in many cases.

Why does this logic apply to localio, but not to normal NFSv4 access?

NeilBrown
Jeff Layton July 2, 2024, 12:29 a.m. UTC | #3
On Tue, 2024-07-02 at 09:55 +1000, NeilBrown wrote:
> On Mon, 01 Jul 2024, Jeff Layton wrote:
> > 
> > Neil, in an earlier email you mentioned that the client could hold onto
> > the nfsd_file reference over several operations and then put it. That
> > would be fine too, but I'm unclear on how the client will manage this.
> > Does the client have a way to keep track of the nfsd_file over several
> > operations to the same inode?
> 
> Looking at 
>    [PATCH v10 13/19] nfs: add "localio" support
> 
> you can see that 
>    struct file *local_filp;
> is added to "struct nfs_open_context".  An nfs_open_context is stored
> in file->private_data and is attached to the inode via nfsi->open_files.
> It holds the nfs state for any file open on the NFS filesystem..
> 
> ->local_filp is set the first time nfs_local_file_open_cache() is called
> and remains set until the final __put_nfs_open_context() call destroys
> the context.  So it lasts as long as the NFS file is open.  Note that
> only one successful ->nfsd_open_local_fh() call is made for each opened
> NFS file.  All IO then uses the "struct file*" with no further reference
> to nfsd.
> 
> If we stored an nfsd_file in the nfs_open_context, either as well as
> the 'struct file*' or instead of, then we could call nfsd_file_put()
> when the nfs file is closed.  That seems to be the correct lifetime and
> matches (almost) exactly what happens with NFSv4 where OPEN and CLOSE
> are send over the wire.
> 

Ok.

> > 
> > Even then, I still think we're probably better off just garbage
> > collecting thse, since it seems likely that they will end up being
> > reused in many cases.
> 
> Why does this logic apply to localio, but not to normal NFSv4 access?
> 

The main idea with the filecache was to keep open files around for a
little while to reduce the open/close overhead between v3 RPCs. The
argument for not caching files with v4 is that we have an open stateid
that pins the open file in place, so we don't need to do that there.

Hanging an nfsd_file off of the nfs client's open_context sounds like a
reasonable alternative.
kernel test robot July 4, 2024, 8:58 a.m. UTC | #4
Hello,

kernel test robot noticed "BUG:kernel_NULL_pointer_dereference,address" on:

commit: 23fc4a797ca65dbe32393093e546c23c0cf278c1 ("[PATCH 6/6] nfsd: add nfsd_file_acquire_local().")
url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfsd-introduce-__fh_verify-which-takes-explicit-nfsd_net-arg/20240701-122856
base: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git 22a40d14b572deb80c0648557f4bd502d7e83826
patch link: https://lore.kernel.org/all/20240701025802.22985-7-neilb@suse.de/
patch subject: [PATCH 6/6] nfsd: add nfsd_file_acquire_local().

in testcase: filebench
version: filebench-x86_64-22620e6-1_20240224
with following parameters:

	disk: 1HDD
	fs: btrfs
	fs2: nfsv4
	test: singlestreamwritedirect.f
	cpufreq_governor: performance



compiler: gcc-13
test machine: 128 threads 2 sockets Intel(R) Xeon(R) Platinum 8358 CPU @ 2.60GHz (Ice Lake) with 128G memory

(please refer to attached dmesg/kmsg for entire log/backtrace)



If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202407041659.c2371438-oliver.sang@intel.com


[   35.440736][ T2585] BUG: kernel NULL pointer dereference, address: 0000000000000010
[   35.449115][ T2585] #PF: supervisor read access in kernel mode
[   35.455679][ T2585] #PF: error_code(0x0000) - not-present page
[   35.461966][ T2585] PGD 0
[   35.465163][ T2585] Oops: Oops: 0000 [#1] SMP NOPTI
[   35.470524][ T2585] CPU: 40 PID: 2585 Comm: nfsd Tainted: G S                 6.10.0-rc6-00006-g23fc4a797ca6 #1
[   35.481056][ T2585] Hardware name: Intel Corporation M50CYP2SB1U/M50CYP2SB1U, BIOS SE5C620.86B.01.01.0003.2104260124 04/26/2021
[ 35.493034][ T2585] RIP: 0010:nfsexp_flags (fs/nfsd/auth.c:14) nfsd
[ 35.499118][ T2585] Code: 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 66 0f 1f 00 0f 1f 44 00 00 8b 56 78 48 8d 46 7c 48 8d 14 d0 48 39 d0 73 1a <8b> 4f 10 eb 09 48 83 c0 08 48 39 d0 73 0c 39 08 75 f3 8b 40 04 c3
All code
========
   0:	00 90 90 90 90 90    	add    %dl,-0x6f6f6f70(%rax)
   6:	90                   	nop
   7:	90                   	nop
   8:	90                   	nop
   9:	90                   	nop
   a:	90                   	nop
   b:	90                   	nop
   c:	90                   	nop
   d:	90                   	nop
   e:	90                   	nop
   f:	90                   	nop
  10:	90                   	nop
  11:	66 0f 1f 00          	nopw   (%rax)
  15:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  1a:	8b 56 78             	mov    0x78(%rsi),%edx
  1d:	48 8d 46 7c          	lea    0x7c(%rsi),%rax
  21:	48 8d 14 d0          	lea    (%rax,%rdx,8),%rdx
  25:	48 39 d0             	cmp    %rdx,%rax
  28:	73 1a                	jae    0x44
  2a:*	8b 4f 10             	mov    0x10(%rdi),%ecx		<-- trapping instruction
  2d:	eb 09                	jmp    0x38
  2f:	48 83 c0 08          	add    $0x8,%rax
  33:	48 39 d0             	cmp    %rdx,%rax
  36:	73 0c                	jae    0x44
  38:	39 08                	cmp    %ecx,(%rax)
  3a:	75 f3                	jne    0x2f
  3c:	8b 40 04             	mov    0x4(%rax),%eax
  3f:	c3                   	retq   

Code starting with the faulting instruction
===========================================
   0:	8b 4f 10             	mov    0x10(%rdi),%ecx
   3:	eb 09                	jmp    0xe
   5:	48 83 c0 08          	add    $0x8,%rax
   9:	48 39 d0             	cmp    %rdx,%rax
   c:	73 0c                	jae    0x1a
   e:	39 08                	cmp    %ecx,(%rax)
  10:	75 f3                	jne    0x5
  12:	8b 40 04             	mov    0x4(%rax),%eax
  15:	c3                   	retq   
[   35.519118][ T2585] RSP: 0018:ffa000000b48fb18 EFLAGS: 00010283
[   35.525649][ T2585] RAX: ff11001086c8d47c RBX: 0000000000000000 RCX: 0000000000000000
[   35.534071][ T2585] RDX: ff11001086c8d484 RSI: ff11001086c8d400 RDI: 0000000000000000
[   35.542422][ T2585] RBP: ff11001086c8d400 R08: 0000000000000000 R09: ff11000128adb500
[   35.550760][ T2585] R10: ffa000000b48fc00 R11: ff11000154660160 R12: ff11000154660000
[   35.559184][ T2585] R13: ff11001086c8d400 R14: ff11001086cb7800 R15: 0000000000008000
[   35.567487][ T2585] FS:  0000000000000000(0000) GS:ff11002000200000(0000) knlGS:0000000000000000
[   35.576800][ T2585] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   35.583895][ T2585] CR2: 0000000000000010 CR3: 000000207de1c002 CR4: 0000000000771ef0
[   35.592300][ T2585] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   35.600610][ T2585] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   35.609052][ T2585] PKRU: 55555554
[   35.612962][ T2585] Call Trace:
[   35.616640][ T2585]  <TASK>
[ 35.620001][ T2585] ? __die (arch/x86/kernel/dumpstack.c:421 arch/x86/kernel/dumpstack.c:434) 
[ 35.624224][ T2585] ? page_fault_oops (arch/x86/mm/fault.c:715) 
[ 35.629458][ T2585] ? exc_page_fault (arch/x86/include/asm/irqflags.h:37 arch/x86/include/asm/irqflags.h:72 arch/x86/mm/fault.c:1489 arch/x86/mm/fault.c:1539) 
[ 35.634666][ T2585] ? asm_exc_page_fault (arch/x86/include/asm/idtentry.h:623) 
[ 35.640019][ T2585] ? nfsexp_flags (fs/nfsd/auth.c:14) nfsd
[ 35.645521][ T2585] nfsd_setuser_and_check_port (fs/nfsd/nfsfh.c:109) nfsd
[ 35.652274][ T2585] __fh_verify (fs/nfsd/nfsfh.c:372) nfsd
[ 35.657656][ T2585] nfsd_file_do_acquire (fs/nfsd/filecache.c:997) nfsd
[ 35.663821][ T2585] nfsd_file_acquire_opened (fs/nfsd/filecache.c:1235 (discriminator 1)) nfsd
[ 35.670245][ T2585] nfs4_get_vfs_file (fs/nfsd/nfs4state.c:5557) nfsd
[ 35.676256][ T2585] nfsd4_process_open2 (fs/nfsd/nfs4state.c:6098) nfsd
[ 35.682411][ T2585] nfsd4_open (fs/nfsd/nfs4proc.c:624) nfsd
[ 35.687758][ T2585] nfsd4_proc_compound (fs/nfsd/nfs4proc.c:2776) nfsd
[ 35.693946][ T2585] nfsd_dispatch (fs/nfsd/nfssvc.c:1004) nfsd
[ 35.699460][ T2585] svc_process_common (net/sunrpc/svc.c:1391) 
[ 35.704884][ T2585] ? __pfx_nfsd_dispatch (fs/nfsd/nfssvc.c:961) nfsd
[ 35.711172][ T2585] svc_process (net/sunrpc/svc.c:1537 (discriminator 1)) 
[ 35.715880][ T2585] svc_handle_xprt (net/sunrpc/svc_xprt.c:831) 
[ 35.721128][ T2585] svc_recv (include/linux/sunrpc/bc_xprt.h:40 net/sunrpc/svc_xprt.c:892) 
[ 35.725731][ T2585] ? __pfx_nfsd (fs/nfsd/nfssvc.c:910) nfsd
[ 35.731143][ T2585] nfsd (fs/nfsd/nfssvc.c:939) nfsd
[ 35.735821][ T2585] kthread (kernel/kthread.c:389) 
[ 35.740131][ T2585] ? __pfx_kthread (kernel/kthread.c:342) 
[ 35.745176][ T2585] ret_from_fork (arch/x86/kernel/process.c:147) 
[ 35.750004][ T2585] ? __pfx_kthread (kernel/kthread.c:342) 
[ 35.754945][ T2585] ret_from_fork_asm (arch/x86/entry/entry_64.S:257) 
[   35.760136][ T2585]  </TASK>
[   35.763428][ T2585] Modules linked in: rpcsec_gss_krb5 nfsv4 dns_resolver nfsd auth_rpcgss device_dax(+) nd_pmem nd_btt dax_pmem btrfs blake2b_generic xor raid6_pq libcrc32c intel_rapl_msr intel_rapl_common x86_pkg_temp_thermal intel_powerclamp sd_mod coretemp t10_pi crc64_rocksoft_generic crc64_rocksoft crc64 kvm_intel sg kvm crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel sha512_ssse3 rapl ahci ast libahci acpi_power_meter intel_cstate ipmi_ssif mei_me drm_shmem_helper intel_th_gth intel_th_pci ioatdma i2c_i801 intel_uncore dax_hmem libata drm_kms_helper ipmi_si acpi_ipmi mei i2c_smbus intel_pch_thermal intel_th wmi dca nfit ipmi_devintf libnvdimm ipmi_msghandler acpi_pad joydev binfmt_misc drm fuse loop dm_mod ip_tables
[   35.830582][ T2585] CR2: 0000000000000010
[   35.835241][ T2585] ---[ end trace 0000000000000000 ]---
[   35.849208][ T2585] pstore: backend (erst) writing error (-28)
[ 35.855581][ T2585] RIP: 0010:nfsexp_flags (fs/nfsd/auth.c:14) nfsd
[ 35.861704][ T2585] Code: 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 66 0f 1f 00 0f 1f 44 00 00 8b 56 78 48 8d 46 7c 48 8d 14 d0 48 39 d0 73 1a <8b> 4f 10 eb 09 48 83 c0 08 48 39 d0 73 0c 39 08 75 f3 8b 40 04 c3
All code
========
   0:	00 90 90 90 90 90    	add    %dl,-0x6f6f6f70(%rax)
   6:	90                   	nop
   7:	90                   	nop
   8:	90                   	nop
   9:	90                   	nop
   a:	90                   	nop
   b:	90                   	nop
   c:	90                   	nop
   d:	90                   	nop
   e:	90                   	nop
   f:	90                   	nop
  10:	90                   	nop
  11:	66 0f 1f 00          	nopw   (%rax)
  15:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  1a:	8b 56 78             	mov    0x78(%rsi),%edx
  1d:	48 8d 46 7c          	lea    0x7c(%rsi),%rax
  21:	48 8d 14 d0          	lea    (%rax,%rdx,8),%rdx
  25:	48 39 d0             	cmp    %rdx,%rax
  28:	73 1a                	jae    0x44
  2a:*	8b 4f 10             	mov    0x10(%rdi),%ecx		<-- trapping instruction
  2d:	eb 09                	jmp    0x38
  2f:	48 83 c0 08          	add    $0x8,%rax
  33:	48 39 d0             	cmp    %rdx,%rax
  36:	73 0c                	jae    0x44
  38:	39 08                	cmp    %ecx,(%rax)
  3a:	75 f3                	jne    0x2f
  3c:	8b 40 04             	mov    0x4(%rax),%eax
  3f:	c3                   	retq   

Code starting with the faulting instruction
===========================================
   0:	8b 4f 10             	mov    0x10(%rdi),%ecx
   3:	eb 09                	jmp    0xe
   5:	48 83 c0 08          	add    $0x8,%rax
   9:	48 39 d0             	cmp    %rdx,%rax
   c:	73 0c                	jae    0x1a
   e:	39 08                	cmp    %ecx,(%rax)
  10:	75 f3                	jne    0x5
  12:	8b 40 04             	mov    0x4(%rax),%eax
  15:	c3                   	retq   


The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20240704/202407041659.c2371438-oliver.sang@intel.com
diff mbox series

Patch

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index ad9083ca144b..87f965d2574b 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -977,7 +977,10 @@  nfsd_file_is_cached(struct inode *inode)
 }
 
 static __be32
-nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+nfsd_file_do_acquire(struct svc_rqst *rqstp, struct nfsd_net *nn,
+		     struct svc_cred *cred, int nfs_vers,
+		     struct auth_domain *client,
+		     struct svc_fh *fhp,
 		     unsigned int may_flags, struct file *file,
 		     struct nfsd_file **pnf, bool want_gc)
 {
@@ -991,7 +994,7 @@  nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	int ret;
 
 retry:
-	status = fh_verify(rqstp, fhp, S_IFREG,
+	status = __fh_verify(rqstp, nn, cred, nfs_vers, client, fhp, S_IFREG,
 				may_flags|NFSD_MAY_OWNER_OVERRIDE);
 	if (status != nfs_ok)
 		return status;
@@ -1139,7 +1142,8 @@  __be32
 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		     unsigned int may_flags, struct nfsd_file **pnf)
 {
-	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
+	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL,
+				    fhp, may_flags, NULL, pnf, true);
 }
 
 /**
@@ -1163,7 +1167,46 @@  __be32
 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		  unsigned int may_flags, struct nfsd_file **pnf)
 {
-	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
+	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL, fhp,
+				    may_flags, NULL, pnf, false);
+}
+
+/**
+ * nfsd_file_acquire_local - Get a struct nfsd_file with an open file for localio
+ * @nn: The nfsd network namespace in which to perform a lookup
+ * @cred: the user credential with which to validate access
+ * @nfs_vers: NFS version number to assume for request
+ * @client: the auth_domain for LOCALIO lookup
+ * @fhp: the NFS filehandle of the file to be opened
+ * @may_flags: NFSD_MAY_ settings for the file
+ * @pnf: OUT: new or found "struct nfsd_file" object
+ *
+ * This file lookup interface provide access to a file given the
+ * filehandle and credential.  No connection-based authorisation
+ * is performed and in that way it is quite different to other
+ * file access mediated by nfsd.  It allows a kernel module such as the NFS
+ * client to reach across network and filesystem namespaces to access
+ * a file.  The security implications of this should be carefully
+ * considered before use.
+ *
+ * The nfsd_file_object returned by this API is reference-counted
+ * but not garbage-collected. The object is unhashed after the
+ * final nfsd_file_put().
+ *
+ * Return values:
+ *   %nfs_ok - @pnf points to an nfsd_file with its reference
+ *   count boosted.
+ *
+ * On error, an nfsstat value in network byte order is returned.
+ */
+__be32
+nfsd_file_acquire_local(struct nfsd_net *nn, struct svc_cred *cred,
+			int nfs_vers, struct auth_domain *client,
+			struct svc_fh *fhp,
+			unsigned int may_flags, struct nfsd_file **pnf)
+{
+	return nfsd_file_do_acquire(NULL, nn, cred, nfs_vers, client,
+				    fhp, may_flags, NULL, pnf, false);
 }
 
 /**
@@ -1189,7 +1232,8 @@  nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
 			 unsigned int may_flags, struct file *file,
 			 struct nfsd_file **pnf)
 {
-	return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
+	return nfsd_file_do_acquire(rqstp, NULL, NULL, 0, NULL,
+				    fhp, may_flags, file, pnf, false);
 }
 
 /*
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index c61884def906..d179dbae98e3 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -65,5 +65,9 @@  __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
 __be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		  unsigned int may_flags, struct file *file,
 		  struct nfsd_file **nfp);
+__be32 nfsd_file_acquire_local(struct nfsd_net *nn, struct svc_cred *cred,
+			       int nfs_vers, struct auth_domain *client,
+			       struct svc_fh *fhp,
+			       unsigned int may_flags, struct nfsd_file **pnf);
 int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
 #endif /* _FS_NFSD_FILECACHE_H */
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index fb5a23060a4c..fa7e358d91ab 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -328,7 +328,7 @@  static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn,
  * @access is formed from the NFSD_MAY_* constants defined in
  * fs/nfsd/vfs.h.
  */
-static __be32
+__be32
 __fh_verify(struct svc_rqst *rqstp,
 	    struct nfsd_net *nn, struct svc_cred *cred,
 	    int nfs_vers, struct auth_domain *client,
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 6ebdf7ea27bf..a2d9962f1bf8 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -214,7 +214,12 @@  extern char * SVCFH_fmt(struct svc_fh *fhp);
 /*
  * Function prototypes
  */
+struct nfsd_net;
 __be32	fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
+__be32	__fh_verify(struct svc_rqst *rqstp,
+		    struct nfsd_net *nn, struct svc_cred *cred,
+		    int nfs_vers, struct auth_domain *client,
+		    struct svc_fh *fhp, umode_t type, int access);
 __be32	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
 __be32	fh_update(struct svc_fh *);
 void	fh_put(struct svc_fh *);