Skip to content

Commit

Permalink
NAS-132120 / 25.04 / expose ZFS snapdir over NFS (#207)
Browse files Browse the repository at this point in the history
This commit adds support for auto-mounting ZFS snapshot directories
as they are accessed over the NFS protocol if the export option
NFSEXP_SNAPDIR has been set.

Signed-off-by: Andrew Walker <[email protected]>
  • Loading branch information
anodos325 authored Feb 12, 2025
1 parent cce2e7b commit d5db3d6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
52 changes: 52 additions & 0 deletions fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,43 @@ nfserrno (int errno)
return nfserr_io;
}

/*
* Called from nfsd_cross_mnt and is used to determine
* whether we need to set LOOKUP_AUTOMOUNT flag.
*
* ZFSCTL_INO_SNAPDIR is defined in sys/zfs_ctldir.h
* and is unlikely to change. This is a hard-coded inode
* number for .zfs/snapshot directory in the ZFS ctldir.
*
* If we know the parent inode number is the snapdir then
* we also know that the current dentry is for an auto-
* mounted snapshot.
*/
#if CONFIG_TRUENAS
static int
is_in_zfs_snapdir(struct dentry *dentry)
{
#define ZFSCTL_INO_SNAPDIR 0x0000FFFFFFFFFFFDULL

struct dentry *dp = dentry->d_parent;
struct inode *inode = NULL;

if (dp == NULL)
return 0;

inode = d_inode(dp);
if (inode == NULL)
return 0;

// Currently only ZFS has large xattr support enabled.
if (!IS_LARGE_XATTR(inode))
return 0;

// The ZFS snapdir has a hard-coded inode value
return (inode->i_ino == ZFSCTL_INO_SNAPDIR);
}
#endif /* CONFIG_TRUENAS */

/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
Expand All @@ -127,11 +164,21 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct path path = {.mnt = mntget(exp->ex_path.mnt),
.dentry = dget(dentry)};
unsigned int follow_flags = 0;
int is_snapdir = 0;
int err = 0;

if (exp->ex_flags & NFSEXP_CROSSMOUNT)
follow_flags = LOOKUP_AUTOMOUNT;

#if CONFIG_TRUENAS
// ZFS ctldir specific handling
if (exp->ex_flags & NFSEXP_SNAPDIR) {
is_snapdir = is_in_zfs_snapdir(dentry);
if (is_snapdir)
follow_flags = LOOKUP_AUTOMOUNT;
}
#endif /* CONFIG_TRUENAS */

err = follow_down(&path, follow_flags);
if (err < 0)
goto out;
Expand All @@ -157,7 +204,12 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
path_put(&path);
goto out;
}

#if CONFIG_TRUENAS
if (nfsd_v4client(rqstp) || is_snapdir ||
#else
if (nfsd_v4client(rqstp) ||
#endif /* CONFIG_TRUENAS */
(exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
/* successfully crossed mount point */
/*
Expand Down
3 changes: 2 additions & 1 deletion include/uapi/linux/nfsd/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@
*/
#define NFSEXP_V4ROOT 0x10000
#define NFSEXP_PNFS 0x20000
#define NFSEXP_SNAPDIR 0x40000 /* Expose the ZFS snapshot directory over NFS */

/* All flags that we claim to support. (Note we don't support NOACL.) */
#define NFSEXP_ALLFLAGS 0x3FEFF
#define NFSEXP_ALLFLAGS 0x7FEFF

/* The flags that may vary depending on security flavor: */
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
Expand Down

0 comments on commit d5db3d6

Please sign in to comment.