diff mbox series

[v2,2/4] exportfs: make ->encode_fh() a mandatory method for NFS export

Message ID 20231023180801.2953446-3-amir73il@gmail.com (mailing list archive)
State New, archived
Headers show
Series Support more filesystems with FAN_REPORT_FID | expand

Commit Message

Amir Goldstein Oct. 23, 2023, 6:07 p.m. UTC
export_operations ->encode_fh() no longer has a default implementation to
encode FILEID_INO32_GEN* file handles.

Rename the default helper for encoding FILEID_INO32_GEN* file handles to
generic_encode_ino32_fh() and convert the filesystems that used the
default implementation to use the generic helper explicitly.

This is a step towards allowing filesystems to encode non-decodeable file
handles for fanotify without having to implement any export_operations.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 Documentation/filesystems/nfs/exporting.rst |  7 ++-----
 Documentation/filesystems/porting.rst       |  9 +++++++++
 fs/affs/namei.c                             |  1 +
 fs/befs/linuxvfs.c                          |  1 +
 fs/efs/super.c                              |  1 +
 fs/erofs/super.c                            |  1 +
 fs/exportfs/expfs.c                         | 16 +++++++++-------
 fs/ext2/super.c                             |  1 +
 fs/ext4/super.c                             |  1 +
 fs/f2fs/super.c                             |  1 +
 fs/fat/nfs.c                                |  1 +
 fs/jffs2/super.c                            |  1 +
 fs/jfs/super.c                              |  1 +
 fs/ntfs/namei.c                             |  1 +
 fs/ntfs3/super.c                            |  1 +
 fs/smb/client/export.c                      | 11 +++++------
 fs/squashfs/export.c                        |  1 +
 fs/ufs/super.c                              |  1 +
 include/linux/exportfs.h                    |  9 ++++++++-
 19 files changed, 47 insertions(+), 19 deletions(-)

Comments

Dave Kleikamp Oct. 24, 2023, 3:08 p.m. UTC | #1
On 10/23/23 1:07PM, Amir Goldstein wrote:
> export_operations ->encode_fh() no longer has a default implementation to
> encode FILEID_INO32_GEN* file handles.
> 
> Rename the default helper for encoding FILEID_INO32_GEN* file handles to
> generic_encode_ino32_fh() and convert the filesystems that used the
> default implementation to use the generic helper explicitly.
> 
> This is a step towards allowing filesystems to encode non-decodeable file
> handles for fanotify without having to implement any export_operations.
> 
> Reviewed-by: Jan Kara <jack@suse.cz>
> Reviewed-by: Jeff Layton <jlayton@kernel.org>
> Acked-by: Chuck Lever <chuck.lever@oracle.com>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>

Acked-by: Dave Kleikamp <dave.kleikamp@oracle.com>
> ---
>   Documentation/filesystems/nfs/exporting.rst |  7 ++-----
>   Documentation/filesystems/porting.rst       |  9 +++++++++
>   fs/affs/namei.c                             |  1 +
>   fs/befs/linuxvfs.c                          |  1 +
>   fs/efs/super.c                              |  1 +
>   fs/erofs/super.c                            |  1 +
>   fs/exportfs/expfs.c                         | 16 +++++++++-------
>   fs/ext2/super.c                             |  1 +
>   fs/ext4/super.c                             |  1 +
>   fs/f2fs/super.c                             |  1 +
>   fs/fat/nfs.c                                |  1 +
>   fs/jffs2/super.c                            |  1 +
>   fs/jfs/super.c                              |  1 +
>   fs/ntfs/namei.c                             |  1 +
>   fs/ntfs3/super.c                            |  1 +
>   fs/smb/client/export.c                      | 11 +++++------
>   fs/squashfs/export.c                        |  1 +
>   fs/ufs/super.c                              |  1 +
>   include/linux/exportfs.h                    |  9 ++++++++-
>   19 files changed, 47 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst
> index 4b30daee399a..de64d2d002a2 100644
> --- a/Documentation/filesystems/nfs/exporting.rst
> +++ b/Documentation/filesystems/nfs/exporting.rst
> @@ -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
> diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
> index 4d05b9862451..9cc6cb27c4d5 100644
> --- a/Documentation/filesystems/porting.rst
> +++ b/Documentation/filesystems/porting.rst
> @@ -1045,3 +1045,12 @@ filesystem type is now moved to a later point when the devices are closed:
>   As this is a VFS level change it has no practical consequences for filesystems
>   other than that all of them must use one of the provided kill_litter_super(),
>   kill_anon_super(), or kill_block_super() helpers.
> +
> +---
> +
> +**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.
> diff --git a/fs/affs/namei.c b/fs/affs/namei.c
> index 2fe4a5832fcf..d6b9758ee23d 100644
> --- a/fs/affs/namei.c
> +++ b/fs/affs/namei.c
> @@ -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,
> diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
> index 9a16a51fbb88..410dcaffd5ab 100644
> --- a/fs/befs/linuxvfs.c
> +++ b/fs/befs/linuxvfs.c
> @@ -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,
> diff --git a/fs/efs/super.c b/fs/efs/super.c
> index b287f47c165b..f17fdac76b2e 100644
> --- a/fs/efs/super.c
> +++ b/fs/efs/super.c
> @@ -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,
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 3700af9ee173..edbe07a24156 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -626,6 +626,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,
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 9ee205df8fa7..8f883c4758f5 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -343,20 +343,21 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
>   }
>   
>   /**
> - * export_encode_fh - default export_operations->encode_fh function
> + * generic_encode_ino32_fh - generic export_operations->encode_fh function
>    * @inode:   the object to encode
> - * @fid:     where to store the file handle fragment
> - * @max_len: maximum length to store there
> + * @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 default encode_fh function assumes that the 32 inode number
> + * 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.
>    */
> -static int export_encode_fh(struct inode *inode, struct fid *fid,
> -		int *max_len, struct inode *parent)
> +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;
>   
> @@ -380,6 +381,7 @@ static int export_encode_fh(struct inode *inode, struct fid *fid,
>   	*max_len = len;
>   	return type;
>   }
> +EXPORT_SYMBOL_GPL(generic_encode_ino32_fh);
>   
>   /**
>    * exportfs_encode_inode_fh - encode a file handle from inode
> @@ -402,7 +404,7 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
>   	if (nop && nop->encode_fh)
>   		return nop->encode_fh(inode, fid->raw, max_len, parent);
>   
> -	return export_encode_fh(inode, fid, max_len, parent);
> +	return -EOPNOTSUPP;
>   }
>   EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
>   
> diff --git a/fs/ext2/super.c b/fs/ext2/super.c
> index aaf3e3e88cb2..b9f158a34997 100644
> --- a/fs/ext2/super.c
> +++ b/fs/ext2/super.c
> @@ -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,
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index dbebd8b3127e..c44db1915437 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1646,6 +1646,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,
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index a8c8232852bb..60cfa11f65bf 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -3282,6 +3282,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,
> diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c
> index 3626eb585a98..c52e63e10d35 100644
> --- a/fs/fat/nfs.c
> +++ b/fs/fat/nfs.c
> @@ -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,
> diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
> index 7ea37f49f1e1..f99591a634b4 100644
> --- a/fs/jffs2/super.c
> +++ b/fs/jffs2/super.c
> @@ -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,
> diff --git a/fs/jfs/super.c b/fs/jfs/super.c
> index 2e2f7f6d36a0..2cc2632f3c47 100644
> --- a/fs/jfs/super.c
> +++ b/fs/jfs/super.c
> @@ -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,
> diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
> index ab44f2db533b..d7498ddc4a72 100644
> --- a/fs/ntfs/namei.c
> +++ b/fs/ntfs/namei.c
> @@ -384,6 +384,7 @@ static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
>    * and due to using iget() whereas NTFS needs ntfs_iget().
>    */
>   const struct export_operations ntfs_export_ops = {
> +	.encode_fh	= generic_encode_ino32_fh,
>   	.get_parent	= ntfs_get_parent,	/* Find the parent of a given
>   						   directory. */
>   	.fh_to_dentry	= ntfs_fh_to_dentry,
> diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
> index 5661a363005e..661ffb5aa1e0 100644
> --- a/fs/ntfs3/super.c
> +++ b/fs/ntfs3/super.c
> @@ -789,6 +789,7 @@ static int ntfs_nfs_commit_metadata(struct inode *inode)
>   }
>   
>   static const struct export_operations ntfs_export_ops = {
> +	.encode_fh = generic_encode_ino32_fh,
>   	.fh_to_dentry = ntfs_fh_to_dentry,
>   	.fh_to_parent = ntfs_fh_to_parent,
>   	.get_parent = ntfs3_get_parent,
> diff --git a/fs/smb/client/export.c b/fs/smb/client/export.c
> index 37c28415df1e..d606e8cbcb7d 100644
> --- a/fs/smb/client/export.c
> +++ b/fs/smb/client/export.c
> @@ -41,13 +41,12 @@ static struct dentry *cifs_get_parent(struct dentry *dentry)
>   }
>   
>   const struct export_operations cifs_export_ops = {
> +	.encode_fh = generic_encode_ino32_fh,
>   	.get_parent = cifs_get_parent,
> -/*	Following five export operations are unneeded so far and can default:
> -	.get_dentry =
> -	.get_name =
> -	.find_exported_dentry =
> -	.decode_fh =
> -	.encode_fs =  */
> +/*
> + * Following export operations are mandatory for NFS export support:
> + *	.fh_to_dentry =
> + */
>   };
>   
>   #endif /* CONFIG_CIFS_NFSD_EXPORT */
> diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c
> index 723763746238..62972f0ff868 100644
> --- a/fs/squashfs/export.c
> +++ b/fs/squashfs/export.c
> @@ -173,6 +173,7 @@ __le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
>   
>   
>   const struct export_operations squashfs_export_ops = {
> +	.encode_fh = generic_encode_ino32_fh,
>   	.fh_to_dentry = squashfs_fh_to_dentry,
>   	.fh_to_parent = squashfs_fh_to_parent,
>   	.get_parent = squashfs_get_parent
> diff --git a/fs/ufs/super.c b/fs/ufs/super.c
> index 23377c1baed9..a480810cd4e3 100644
> --- a/fs/ufs/super.c
> +++ b/fs/ufs/super.c
> @@ -137,6 +137,7 @@ static struct dentry *ufs_get_parent(struct dentry *child)
>   }
>   
>   static const struct export_operations ufs_export_ops = {
> +	.encode_fh = generic_encode_ino32_fh,
>   	.fh_to_dentry	= ufs_fh_to_dentry,
>   	.fh_to_parent	= ufs_fh_to_parent,
>   	.get_parent	= ufs_get_parent,
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 5b3c9f30b422..85bd027494e5 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -235,7 +235,7 @@ extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
>   
>   static inline bool exportfs_can_encode_fid(const struct export_operations *nop)
>   {
> -	return nop;
> +	return nop && nop->encode_fh;
>   }
>   
>   static inline bool exportfs_can_decode_fh(const struct export_operations *nop)
> @@ -279,6 +279,13 @@ extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
>   /*
>    * Generic helpers for filesystems.
>    */
> +#ifdef CONFIG_EXPORTFS
> +int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len,
> +			    struct inode *parent);
> +#else
> +#define generic_encode_ino32_fh NULL
> +#endif
> +
>   extern struct dentry *generic_fh_to_dentry(struct super_block *sb,
>   	struct fid *fid, int fh_len, int fh_type,
>   	struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
Christoph Hellwig Oct. 27, 2023, 6:03 a.m. UTC | #2
On Mon, Oct 23, 2023 at 09:07:59PM +0300, Amir Goldstein wrote:
> export_operations ->encode_fh() no longer has a default implementation to
> encode FILEID_INO32_GEN* file handles.

This statement reads like a factual statement about the current tree.
I'd suggest rewording it to make clear that you are changing the
behavior so that the defaul goes away, and I'd also suggest to move
it after the next paragraph.
Amir Goldstein Oct. 27, 2023, 7:09 a.m. UTC | #3
On Fri, Oct 27, 2023 at 9:03 AM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Mon, Oct 23, 2023 at 09:07:59PM +0300, Amir Goldstein wrote:
> > export_operations ->encode_fh() no longer has a default implementation to
> > encode FILEID_INO32_GEN* file handles.
>
> This statement reads like a factual statement about the current tree.
> I'd suggest rewording it to make clear that you are changing the
> behavior so that the defaul goes away, and I'd also suggest to move
> it after the next paragraph.

Ok. will send v3 with those changes.

Thanks,
Amir.
Christian Brauner Oct. 28, 2023, 2:16 p.m. UTC | #4
> Actually, Christian, since you already picked up the build fix and
> MAINTAINERS patch, cloud I bother you to fixup the commit
> message of this patch according to Christoph's request:
> 
>     exportfs: make ->encode_fh() a mandatory method for NFS export
> 
>     Rename the default helper for encoding FILEID_INO32_GEN* file handles
>     to generic_encode_ino32_fh() and convert the filesystems that used the
>     default implementation to use the generic helper explicitly.
> 
>     After this change, exportfs_encode_inode_fh() no longer has a default
>     implementation to encode FILEID_INO32_GEN* file handles.
> 
>     This is a step towards allowing filesystems to encode non-decodeable file
>     handles for fanotify without having to implement any export_operations.
> 
> 
> Might as well add hch RVB on patch #1 while at it.

Done, please check in vfs.f_fsid and yell if something is wrong.
Amir Goldstein Oct. 29, 2023, 9:50 a.m. UTC | #5
On Sat, Oct 28, 2023 at 5:16 PM Christian Brauner <brauner@kernel.org> wrote:
>
> > Actually, Christian, since you already picked up the build fix and
> > MAINTAINERS patch, cloud I bother you to fixup the commit
> > message of this patch according to Christoph's request:
> >
> >     exportfs: make ->encode_fh() a mandatory method for NFS export
> >
> >     Rename the default helper for encoding FILEID_INO32_GEN* file handles
> >     to generic_encode_ino32_fh() and convert the filesystems that used the
> >     default implementation to use the generic helper explicitly.
> >
> >     After this change, exportfs_encode_inode_fh() no longer has a default
> >     implementation to encode FILEID_INO32_GEN* file handles.
> >
> >     This is a step towards allowing filesystems to encode non-decodeable file
> >     handles for fanotify without having to implement any export_operations.
> >
> >
> > Might as well add hch RVB on patch #1 while at it.
>
> Done, please check in vfs.f_fsid and yell if something is wrong.

I see no changes.
Maybe you have forgotten to push the branch??

Thanks,
Amir.
Christian Brauner Oct. 30, 2023, 10:26 a.m. UTC | #6
> > Done, please check in vfs.f_fsid and yell if something is wrong.
> 
> I see no changes.
> Maybe you have forgotten to push the branch??

I fixed it all up on Saturday but then didn't push until this morning.
Amir Goldstein Oct. 30, 2023, 5:18 p.m. UTC | #7
On Mon, Oct 30, 2023 at 12:26 PM Christian Brauner <brauner@kernel.org> wrote:
>
> > > Done, please check in vfs.f_fsid and yell if something is wrong.
> >
> > I see no changes.
> > Maybe you have forgotten to push the branch??
>
> I fixed it all up on Saturday but then didn't push until this morning.

Looks good.

Although kernel testbot just complained about the CONFIG_EXORTFS=m build error
in the bisection of the current linux-next, so maybe we should squash
the fix patch.
I have no strong feelings about it, so whatever you decide.

Thanks,
Amir.
diff mbox series

Patch

diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst
index 4b30daee399a..de64d2d002a2 100644
--- a/Documentation/filesystems/nfs/exporting.rst
+++ b/Documentation/filesystems/nfs/exporting.rst
@@ -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
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index 4d05b9862451..9cc6cb27c4d5 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1045,3 +1045,12 @@  filesystem type is now moved to a later point when the devices are closed:
 As this is a VFS level change it has no practical consequences for filesystems
 other than that all of them must use one of the provided kill_litter_super(),
 kill_anon_super(), or kill_block_super() helpers.
+
+---
+
+**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.
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 2fe4a5832fcf..d6b9758ee23d 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -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,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 9a16a51fbb88..410dcaffd5ab 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -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,
diff --git a/fs/efs/super.c b/fs/efs/super.c
index b287f47c165b..f17fdac76b2e 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -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,
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 3700af9ee173..edbe07a24156 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -626,6 +626,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,
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 9ee205df8fa7..8f883c4758f5 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -343,20 +343,21 @@  static int get_name(const struct path *path, char *name, struct dentry *child)
 }
 
 /**
- * export_encode_fh - default export_operations->encode_fh function
+ * generic_encode_ino32_fh - generic export_operations->encode_fh function
  * @inode:   the object to encode
- * @fid:     where to store the file handle fragment
- * @max_len: maximum length to store there
+ * @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 default encode_fh function assumes that the 32 inode number
+ * 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.
  */
-static int export_encode_fh(struct inode *inode, struct fid *fid,
-		int *max_len, struct inode *parent)
+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;
 
@@ -380,6 +381,7 @@  static int export_encode_fh(struct inode *inode, struct fid *fid,
 	*max_len = len;
 	return type;
 }
+EXPORT_SYMBOL_GPL(generic_encode_ino32_fh);
 
 /**
  * exportfs_encode_inode_fh - encode a file handle from inode
@@ -402,7 +404,7 @@  int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
 	if (nop && nop->encode_fh)
 		return nop->encode_fh(inode, fid->raw, max_len, parent);
 
-	return export_encode_fh(inode, fid, max_len, parent);
+	return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
 
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index aaf3e3e88cb2..b9f158a34997 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -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,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index dbebd8b3127e..c44db1915437 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1646,6 +1646,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,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index a8c8232852bb..60cfa11f65bf 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3282,6 +3282,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,
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c
index 3626eb585a98..c52e63e10d35 100644
--- a/fs/fat/nfs.c
+++ b/fs/fat/nfs.c
@@ -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,
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 7ea37f49f1e1..f99591a634b4 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -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,
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 2e2f7f6d36a0..2cc2632f3c47 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -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,
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index ab44f2db533b..d7498ddc4a72 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -384,6 +384,7 @@  static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
  * and due to using iget() whereas NTFS needs ntfs_iget().
  */
 const struct export_operations ntfs_export_ops = {
+	.encode_fh	= generic_encode_ino32_fh,
 	.get_parent	= ntfs_get_parent,	/* Find the parent of a given
 						   directory. */
 	.fh_to_dentry	= ntfs_fh_to_dentry,
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 5661a363005e..661ffb5aa1e0 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -789,6 +789,7 @@  static int ntfs_nfs_commit_metadata(struct inode *inode)
 }
 
 static const struct export_operations ntfs_export_ops = {
+	.encode_fh = generic_encode_ino32_fh,
 	.fh_to_dentry = ntfs_fh_to_dentry,
 	.fh_to_parent = ntfs_fh_to_parent,
 	.get_parent = ntfs3_get_parent,
diff --git a/fs/smb/client/export.c b/fs/smb/client/export.c
index 37c28415df1e..d606e8cbcb7d 100644
--- a/fs/smb/client/export.c
+++ b/fs/smb/client/export.c
@@ -41,13 +41,12 @@  static struct dentry *cifs_get_parent(struct dentry *dentry)
 }
 
 const struct export_operations cifs_export_ops = {
+	.encode_fh = generic_encode_ino32_fh,
 	.get_parent = cifs_get_parent,
-/*	Following five export operations are unneeded so far and can default:
-	.get_dentry =
-	.get_name =
-	.find_exported_dentry =
-	.decode_fh =
-	.encode_fs =  */
+/*
+ * Following export operations are mandatory for NFS export support:
+ *	.fh_to_dentry =
+ */
 };
 
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c
index 723763746238..62972f0ff868 100644
--- a/fs/squashfs/export.c
+++ b/fs/squashfs/export.c
@@ -173,6 +173,7 @@  __le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
 
 
 const struct export_operations squashfs_export_ops = {
+	.encode_fh = generic_encode_ino32_fh,
 	.fh_to_dentry = squashfs_fh_to_dentry,
 	.fh_to_parent = squashfs_fh_to_parent,
 	.get_parent = squashfs_get_parent
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 23377c1baed9..a480810cd4e3 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -137,6 +137,7 @@  static struct dentry *ufs_get_parent(struct dentry *child)
 }
 
 static const struct export_operations ufs_export_ops = {
+	.encode_fh = generic_encode_ino32_fh,
 	.fh_to_dentry	= ufs_fh_to_dentry,
 	.fh_to_parent	= ufs_fh_to_parent,
 	.get_parent	= ufs_get_parent,
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 5b3c9f30b422..85bd027494e5 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -235,7 +235,7 @@  extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
 
 static inline bool exportfs_can_encode_fid(const struct export_operations *nop)
 {
-	return nop;
+	return nop && nop->encode_fh;
 }
 
 static inline bool exportfs_can_decode_fh(const struct export_operations *nop)
@@ -279,6 +279,13 @@  extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
 /*
  * Generic helpers for filesystems.
  */
+#ifdef CONFIG_EXPORTFS
+int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len,
+			    struct inode *parent);
+#else
+#define generic_encode_ino32_fh NULL
+#endif
+
 extern struct dentry *generic_fh_to_dentry(struct super_block *sb,
 	struct fid *fid, int fh_len, int fh_type,
 	struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));