Skip to content

Commit

Permalink
Merge tag 'vfs-6.7.fsid' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/vfs/vfs

Pull vfs fanotify fsid updates from Christian Brauner:
 "This work is part of the plan to enable fanotify to serve as a drop-in
  replacement for inotify. While inotify is availabe on all filesystems,
  fanotify currently isn't.

  In order to support fanotify on all filesystems two things are needed:

   (1) all filesystems need to support AT_HANDLE_FID

   (2) all filesystems need to report a non-zero f_fsid

  This contains (1) and allows filesystems to encode non-decodable file
  handlers for fanotify without implementing any exportfs operations by
  encoding a file id of type FILEID_INO64_GEN from i_ino and
  i_generation.

  Filesystems that want to opt out of encoding non-decodable file ids
  for fanotify that don't support NFS export can do so by providing an
  empty export_operations struct.

  This also partially addresses (2) by generating f_fsid for simple
  filesystems as well as freevxfs. Remaining filesystems will be dealt
  with by separate patches.

  Finally, this contains the patch from the current exportfs maintainers
  which moves exportfs under vfs with Chuck, Jeff, and Amir as
  maintainers and vfs.git as tree"

* tag 'vfs-6.7.fsid' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  MAINTAINERS: create an entry for exportfs
  fs: fix build error with CONFIG_EXPORTFS=m or not defined
  freevxfs: derive f_fsid from bdev->bd_dev
  fs: report f_fsid from s_dev for "simple" filesystems
  exportfs: support encoding non-decodeable file handles by default
  exportfs: define FILEID_INO64_GEN* file handle types
  exportfs: make ->encode_fh() a mandatory method for NFS export
  exportfs: add helpers to check if filesystem can encode/decode file handles
  • Loading branch information
Linus Torvalds committed Nov 7, 2023
2 parents 062cca8 + 4ad714d commit 13d88ac
Show file tree
Hide file tree
Showing 29 changed files with 168 additions and 65 deletions.
7 changes: 2 additions & 5 deletions Documentation/filesystems/nfs/exporting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,9 @@ are exportable by setting the s_export_op field in the struct
super_block. This field must point to a "struct export_operations"
struct which has the following members:

encode_fh (optional)
encode_fh (mandatory)
Takes a dentry and creates a filehandle fragment which may later be used
to find or create a dentry for the same object. The default
implementation creates a filehandle fragment that encodes a 32bit inode
and generation number for the inode encoded, and if necessary the
same information for the parent.
to find or create a dentry for the same object.

fh_to_dentry (mandatory)
Given a filehandle fragment, this should find the implied object and
Expand Down
9 changes: 9 additions & 0 deletions Documentation/filesystems/porting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1052,3 +1052,12 @@ kill_anon_super(), or kill_block_super() helpers.

Lock ordering has been changed so that s_umount ranks above open_mutex again.
All places where s_umount was taken under open_mutex have been fixed up.

---

**mandatory**

export_operations ->encode_fh() no longer has a default implementation to
encode FILEID_INO32_GEN* file handles.
Filesystems that used the default implementation may use the generic helper
generic_encode_ino32_fh() explicitly.
13 changes: 12 additions & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -8156,6 +8156,18 @@ F: include/linux/fs_types.h
F: include/uapi/linux/fs.h
F: include/uapi/linux/openat2.h

FILESYSTEMS [EXPORTFS]
M: Chuck Lever <chuck.lever@oracle.com>
M: Jeff Layton <jlayton@kernel.org>
R: Amir Goldstein <amir73il@gmail.com>
L: linux-fsdevel@vger.kernel.org
L: linux-nfs@vger.kernel.org
S: Supported
F: Documentation/filesystems/nfs/exporting.rst
F: fs/exportfs/
F: fs/fhandle.c
F: include/linux/exportfs.h

FILESYSTEMS [IOMAP]
M: Christian Brauner <brauner@kernel.org>
R: Darrick J. Wong <djwong@kernel.org>
Expand Down Expand Up @@ -11548,7 +11560,6 @@ S: Supported
W: http://nfs.sourceforge.net/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
F: Documentation/filesystems/nfs/
F: fs/exportfs/
F: fs/lockd/
F: fs/nfs_common/
F: fs/nfsd/
Expand Down
1 change: 1 addition & 0 deletions fs/affs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
}

const struct export_operations affs_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = affs_fh_to_dentry,
.fh_to_parent = affs_fh_to_parent,
.get_parent = affs_get_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/befs/linuxvfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static const struct address_space_operations befs_symlink_aops = {
};

static const struct export_operations befs_export_operations = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = befs_fh_to_dentry,
.fh_to_parent = befs_fh_to_parent,
.get_parent = befs_get_parent,
Expand Down
2 changes: 2 additions & 0 deletions fs/efivarfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS;
u64 storage_space, remaining_space, max_variable_size;
u64 id = huge_encode_dev(dentry->d_sb->s_dev);
efi_status_t status;

/* Some UEFI firmware does not implement QueryVariableInfo() */
Expand All @@ -69,6 +70,7 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_blocks = storage_space;
buf->f_bfree = remaining_space;
buf->f_type = dentry->d_sb->s_magic;
buf->f_fsid = u64_to_fsid(id);

/*
* In f_bavail we declare the free space that the kernel will allow writing
Expand Down
1 change: 1 addition & 0 deletions fs/efs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static const struct super_operations efs_superblock_operations = {
};

static const struct export_operations efs_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = efs_fh_to_dentry,
.fh_to_parent = efs_fh_to_parent,
.get_parent = efs_get_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/erofs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ static struct dentry *erofs_get_parent(struct dentry *child)
}

static const struct export_operations erofs_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = erofs_fh_to_dentry,
.fh_to_parent = erofs_fh_to_parent,
.get_parent = erofs_get_parent,
Expand Down
57 changes: 20 additions & 37 deletions fs/exportfs/expfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,43 +342,30 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
return error;
}

#define FILEID_INO64_GEN_LEN 3

/**
* export_encode_fh - default export_operations->encode_fh function
* exportfs_encode_ino64_fid - encode non-decodeable 64bit ino file id
* @inode: the object to encode
* @fid: where to store the file handle fragment
* @max_len: maximum length to store there
* @parent: parent directory inode, if wanted
* @max_len: maximum length to store there (in 4 byte units)
*
* This default encode_fh function assumes that the 32 inode number
* is suitable for locating an inode, and that the generation number
* can be used to check that it is still valid. It places them in the
* filehandle fragment where export_decode_fh expects to find them.
* This generic function is used to encode a non-decodeable file id for
* fanotify for filesystems that do not support NFS export.
*/
static int export_encode_fh(struct inode *inode, struct fid *fid,
int *max_len, struct inode *parent)
static int exportfs_encode_ino64_fid(struct inode *inode, struct fid *fid,
int *max_len)
{
int len = *max_len;
int type = FILEID_INO32_GEN;

if (parent && (len < 4)) {
*max_len = 4;
return FILEID_INVALID;
} else if (len < 2) {
*max_len = 2;
if (*max_len < FILEID_INO64_GEN_LEN) {
*max_len = FILEID_INO64_GEN_LEN;
return FILEID_INVALID;
}

len = 2;
fid->i32.ino = inode->i_ino;
fid->i32.gen = inode->i_generation;
if (parent) {
fid->i32.parent_ino = parent->i_ino;
fid->i32.parent_gen = parent->i_generation;
len = 4;
type = FILEID_INO32_GEN_PARENT;
}
*max_len = len;
return type;
fid->i64.ino = inode->i_ino;
fid->i64.gen = inode->i_generation;
*max_len = FILEID_INO64_GEN_LEN;

return FILEID_INO64_GEN;
}

/**
Expand All @@ -396,17 +383,13 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
{
const struct export_operations *nop = inode->i_sb->s_export_op;

/*
* If a decodeable file handle was requested, we need to make sure that
* filesystem can decode file handles.
*/
if (nop && !(flags & EXPORT_FH_FID) && !nop->fh_to_dentry)
if (!exportfs_can_encode_fh(nop, flags))
return -EOPNOTSUPP;

if (nop && nop->encode_fh)
return nop->encode_fh(inode, fid->raw, max_len, parent);
if (!nop && (flags & EXPORT_FH_FID))
return exportfs_encode_ino64_fid(inode, fid, max_len);

return export_encode_fh(inode, fid, max_len, parent);
return nop->encode_fh(inode, fid->raw, max_len, parent);
}
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);

Expand Down Expand Up @@ -456,7 +439,7 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
/*
* Try to get any dentry for the given file handle from the filesystem.
*/
if (!nop || !nop->fh_to_dentry)
if (!exportfs_can_decode_fh(nop))
return ERR_PTR(-ESTALE);
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
if (IS_ERR_OR_NULL(result))
Expand Down
1 change: 1 addition & 0 deletions fs/ext2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ static struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid,
}

static const struct export_operations ext2_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = ext2_fh_to_dentry,
.fh_to_parent = ext2_fh_to_parent,
.get_parent = ext2_get_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,7 @@ static const struct super_operations ext4_sops = {
};

static const struct export_operations ext4_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = ext4_fh_to_dentry,
.fh_to_parent = ext4_fh_to_parent,
.get_parent = ext4_get_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/f2fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -3330,6 +3330,7 @@ static struct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid,
}

static const struct export_operations f2fs_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = f2fs_fh_to_dentry,
.fh_to_parent = f2fs_fh_to_parent,
.get_parent = f2fs_get_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/fat/nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ static struct dentry *fat_get_parent(struct dentry *child_dir)
}

const struct export_operations fat_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = fat_fh_to_dentry,
.fh_to_parent = fat_fh_to_parent,
.get_parent = fat_get_parent,
Expand Down
6 changes: 1 addition & 5 deletions fs/fhandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@ static long do_sys_name_to_handle(const struct path *path,
/*
* We need to make sure whether the file system support decoding of
* the file handle if decodeable file handle was requested.
* Otherwise, even empty export_operations are sufficient to opt-in
* to encoding FIDs.
*/
if (!path->dentry->d_sb->s_export_op ||
(!(fh_flags & EXPORT_FH_FID) &&
!path->dentry->d_sb->s_export_op->fh_to_dentry))
if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
return -EOPNOTSUPP;

if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
Expand Down
2 changes: 2 additions & 0 deletions fs/freevxfs/vxfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
{
struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb);
struct vxfs_sb *raw_sb = infp->vsi_raw;
u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev);

bufp->f_type = VXFS_SUPER_MAGIC;
bufp->f_bsize = dentry->d_sb->s_blocksize;
Expand All @@ -84,6 +85,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
bufp->f_bavail = 0;
bufp->f_files = 0;
bufp->f_ffree = fs32_to_cpu(infp, raw_sb->vs_ifree);
bufp->f_fsid = u64_to_fsid(id);
bufp->f_namelen = VXFS_NAMELEN;

return 0;
Expand Down
7 changes: 4 additions & 3 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,15 +999,16 @@ static int fuse_encode_fh(struct inode *inode, u32 *fh, int *max_len,
}

*max_len = len;
return parent ? 0x82 : 0x81;
return parent ? FILEID_INO64_GEN_PARENT : FILEID_INO64_GEN;
}

static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
struct fid *fid, int fh_len, int fh_type)
{
struct fuse_inode_handle handle;

if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
if ((fh_type != FILEID_INO64_GEN &&
fh_type != FILEID_INO64_GEN_PARENT) || fh_len < 3)
return NULL;

handle.nodeid = (u64) fid->raw[0] << 32;
Expand All @@ -1021,7 +1022,7 @@ static struct dentry *fuse_fh_to_parent(struct super_block *sb,
{
struct fuse_inode_handle parent;

if (fh_type != 0x82 || fh_len < 6)
if (fh_type != FILEID_INO64_GEN_PARENT || fh_len < 6)
return NULL;

parent.nodeid = (u64) fid->raw[3] << 32;
Expand Down
2 changes: 2 additions & 0 deletions fs/hugetlbfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,9 @@ static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
struct hstate *h = hstate_inode(d_inode(dentry));
u64 id = huge_encode_dev(dentry->d_sb->s_dev);

buf->f_fsid = u64_to_fsid(id);
buf->f_type = HUGETLBFS_MAGIC;
buf->f_bsize = huge_page_size(h);
if (sbinfo) {
Expand Down
1 change: 1 addition & 0 deletions fs/jffs2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ static struct dentry *jffs2_get_parent(struct dentry *child)
}

static const struct export_operations jffs2_export_ops = {
.encode_fh = generic_encode_ino32_fh,
.get_parent = jffs2_get_parent,
.fh_to_dentry = jffs2_fh_to_dentry,
.fh_to_parent = jffs2_fh_to_parent,
Expand Down
1 change: 1 addition & 0 deletions fs/jfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,7 @@ static const struct super_operations jfs_super_operations = {
};

static const struct export_operations jfs_export_operations = {
.encode_fh = generic_encode_ino32_fh,
.fh_to_dentry = jfs_fh_to_dentry,
.fh_to_parent = jfs_fh_to_parent,
.get_parent = jfs_get_parent,
Expand Down
44 changes: 44 additions & 0 deletions fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ EXPORT_SYMBOL(simple_getattr);

int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
{
u64 id = huge_encode_dev(dentry->d_sb->s_dev);

buf->f_fsid = u64_to_fsid(id);
buf->f_type = dentry->d_sb->s_magic;
buf->f_bsize = PAGE_SIZE;
buf->f_namelen = NAME_MAX;
Expand Down Expand Up @@ -1309,6 +1312,47 @@ ssize_t simple_attr_write_signed(struct file *file, const char __user *buf,
}
EXPORT_SYMBOL_GPL(simple_attr_write_signed);

/**
* generic_encode_ino32_fh - generic export_operations->encode_fh function
* @inode: the object to encode
* @fh: where to store the file handle fragment
* @max_len: maximum length to store there (in 4 byte units)
* @parent: parent directory inode, if wanted
*
* This generic encode_fh function assumes that the 32 inode number
* is suitable for locating an inode, and that the generation number
* can be used to check that it is still valid. It places them in the
* filehandle fragment where export_decode_fh expects to find them.
*/
int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len,
struct inode *parent)
{
struct fid *fid = (void *)fh;
int len = *max_len;
int type = FILEID_INO32_GEN;

if (parent && (len < 4)) {
*max_len = 4;
return FILEID_INVALID;
} else if (len < 2) {
*max_len = 2;
return FILEID_INVALID;
}

len = 2;
fid->i32.ino = inode->i_ino;
fid->i32.gen = inode->i_generation;
if (parent) {
fid->i32.parent_ino = parent->i_ino;
fid->i32.parent_gen = parent->i_generation;
len = 4;
type = FILEID_INO32_GEN_PARENT;
}
*max_len = len;
return type;
}
EXPORT_SYMBOL_GPL(generic_encode_ino32_fh);

/**
* generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
* @sb: filesystem to do the file handle conversion on
Expand Down
3 changes: 1 addition & 2 deletions fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,7 @@ static int check_export(struct path *path, int *flags, unsigned char *uuid)
return -EINVAL;
}

if (!inode->i_sb->s_export_op ||
!inode->i_sb->s_export_op->fh_to_dentry) {
if (!exportfs_can_decode_fh(inode->i_sb->s_export_op)) {
dprintk("exp_export: export of invalid fs type.\n");
return -EINVAL;
}
Expand Down
4 changes: 2 additions & 2 deletions fs/notify/fanotify/fanotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -1595,15 +1595,15 @@ static int fanotify_test_fid(struct dentry *dentry, unsigned int flags)
* file handles so user can use name_to_handle_at() to compare fids
* reported with events to the file handle of watched objects.
*/
if (!nop)
if (!exportfs_can_encode_fid(nop))
return -EOPNOTSUPP;

/*
* For sb/mount mark, we also need to make sure that the filesystem
* supports decoding file handles, so user has a way to map back the
* reported fids to filesystem objects.
*/
if (mark_type != FAN_MARK_INODE && !nop->fh_to_dentry)
if (mark_type != FAN_MARK_INODE && !exportfs_can_decode_fh(nop))
return -EOPNOTSUPP;

return 0;
Expand Down
Loading

0 comments on commit 13d88ac

Please sign in to comment.