nfsd: Fix NFS access to .zfs/snapshot snapshots

When a process attempts to access a snapshot under
/<dataset>/.zfs/snapshot, the snapshot is automounted.
However, without this patch, the automount does not
set mnt_exjail, which results in the snapshot not being
accessible over NFS.

This patch defines a new function called vfs_exjail_clone()
which sets mnt_exjail from another mount point and
then uses that function to set mnt_exjail in the snapshot
automount.  A separate patch that is currently a pull request
for OpenZFS, calls this function to fix the problem.

PR:	275200
Reviewed by:	markj
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D42672
This commit is contained in:
Rick Macklem 2023-11-23 07:23:33 -08:00
parent 637e4ef1a6
commit f5f277728a
2 changed files with 39 additions and 0 deletions

View file

@ -3136,6 +3136,41 @@ suspend_all_fs(void)
mtx_unlock(&mountlist_mtx);
}
/*
* Clone the mnt_exjail field to a new mount point.
*/
void
vfs_exjail_clone(struct mount *inmp, struct mount *outmp)
{
struct ucred *cr;
struct prison *pr;
MNT_ILOCK(inmp);
cr = inmp->mnt_exjail;
if (cr != NULL) {
crhold(cr);
MNT_IUNLOCK(inmp);
pr = cr->cr_prison;
sx_slock(&allprison_lock);
if (!prison_isalive(pr)) {
sx_sunlock(&allprison_lock);
crfree(cr);
return;
}
MNT_ILOCK(outmp);
if (outmp->mnt_exjail == NULL) {
outmp->mnt_exjail = cr;
atomic_add_int(&pr->pr_exportcnt, 1);
cr = NULL;
}
MNT_IUNLOCK(outmp);
sx_sunlock(&allprison_lock);
if (cr != NULL)
crfree(cr);
} else
MNT_IUNLOCK(inmp);
}
void
resume_all_fs(void)
{

View file

@ -980,6 +980,9 @@ enum vfs_notify_upper_type {
* exported vnode operations
*/
/* Define this to indicate that vfs_exjail_clone() exists for ZFS to use. */
#define VFS_SUPPORTS_EXJAIL_CLONE 1
int dounmount(struct mount *, uint64_t, struct thread *);
int kernel_mount(struct mntarg *ma, uint64_t flags);
@ -1016,6 +1019,7 @@ int vfs_setpublicfs /* set publicly exported fs */
(struct mount *, struct netexport *, struct export_args *);
void vfs_periodic(struct mount *, int);
int vfs_busy(struct mount *, int);
void vfs_exjail_clone(struct mount *, struct mount *);
void vfs_exjail_delete(struct prison *);
int vfs_export /* process mount export info */
(struct mount *, struct export_args *, bool);