diff mbox series

fs/exfat: add NFS export support

Message ID 20240819121528.70149-1-andrii.polianytsia@globallogic.com (mailing list archive)
State New
Headers show
Series fs/exfat: add NFS export support | expand

Commit Message

andrii.polianytsia@globallogic.com Aug. 19, 2024, 12:15 p.m. UTC
Add NFS export support to the exFAT filesystem by implementing
the necessary export operations in fs/exfat/super.c. Enable
exFAT filesystems to be exported and accessed over NFS, enhancing
their utility in networked environments.

Introduce the exfat_export_ops structure, which includes
functions to handle file handles and inode lookups necessary for NFS
operations.

Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
---
 fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

Comments

Chuck Lever Aug. 19, 2024, 1:31 p.m. UTC | #1
[ ... adding linux-nfs@vger.kernel.org ]

On Mon, Aug 19, 2024 at 03:15:28PM +0300, andrii.polianytsia@globallogic.com wrote:
> Add NFS export support to the exFAT filesystem by implementing
> the necessary export operations in fs/exfat/super.c. Enable
> exFAT filesystems to be exported and accessed over NFS, enhancing
> their utility in networked environments.
> 
> Introduce the exfat_export_ops structure, which includes
> functions to handle file handles and inode lookups necessary for NFS
> operations.

My memory is dim, but I think the reason that exporting exfat isn't
supported already is because it's file handles aren't persistent.

NFS requires that file handles remain the same across server
restarts or umount/mount cycles of the exported file system.


> Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
> Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
> ---
>  fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 65 insertions(+)
> 
> diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> index 323ecebe6f0e..cb6dcafc3007 100644
> --- a/fs/exfat/super.c
> +++ b/fs/exfat/super.c
> @@ -18,6 +18,7 @@
>  #include <linux/nls.h>
>  #include <linux/buffer_head.h>
>  #include <linux/magic.h>
> +#include <linux/exportfs.h>
>  
>  #include "exfat_raw.h"
>  #include "exfat_fs.h"
> @@ -195,6 +196,69 @@ static const struct super_operations exfat_sops = {
>  	.show_options	= exfat_show_options,
>  };
>  
> +/**
> + * exfat_export_get_inode - Get inode for export operations
> + * @sb: Superblock pointer
> + * @ino: Inode number
> + * @generation: Generation number
> + *
> + * Returns pointer to inode or error pointer in case of an error.
> + */
> +static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
> +	u32 generation)
> +{
> +	struct inode *inode = NULL;
> +
> +	if (ino == 0)
> +		return ERR_PTR(-ESTALE);
> +
> +	inode = ilookup(sb, ino);
> +	if (inode && generation && inode->i_generation != generation) {
> +		iput(inode);
> +		return ERR_PTR(-ESTALE);
> +	}
> +
> +	return inode;
> +}
> +
> +/**
> + * exfat_fh_to_dentry - Convert file handle to dentry
> + * @sb: Superblock pointer
> + * @fid: File identifier
> + * @fh_len: Length of the file handle
> + * @fh_type: Type of the file handle
> + *
> + * Returns dentry corresponding to the file handle.
> + */
> +static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
> +	struct fid *fid, int fh_len, int fh_type)
> +{
> +	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> +		exfat_export_get_inode);
> +}
> +
> +/**
> + * exfat_fh_to_parent - Convert file handle to parent dentry
> + * @sb: Superblock pointer
> + * @fid: File identifier
> + * @fh_len: Length of the file handle
> + * @fh_type: Type of the file handle
> + *
> + * Returns parent dentry corresponding to the file handle.
> + */
> +static struct dentry *exfat_fh_to_parent(struct super_block *sb,
> +	struct fid *fid, int fh_len, int fh_type)
> +{
> +	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> +		exfat_export_get_inode);
> +}
> +
> +static const struct export_operations exfat_export_ops = {
> +	.encode_fh = generic_encode_ino32_fh,
> +	.fh_to_dentry = exfat_fh_to_dentry,
> +	.fh_to_parent = exfat_fh_to_parent,
> +};
> +
>  enum {
>  	Opt_uid,
>  	Opt_gid,
> @@ -633,6 +697,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
>  	sb->s_flags |= SB_NODIRATIME;
>  	sb->s_magic = EXFAT_SUPER_MAGIC;
>  	sb->s_op = &exfat_sops;
> +	sb->s_export_op = &exfat_export_ops;
>  
>  	sb->s_time_gran = 10 * NSEC_PER_MSEC;
>  	sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
> -- 
> 2.25.1
> 
>
Namjae Jeon Aug. 19, 2024, 2:21 p.m. UTC | #2
>
> [ ... adding linux-nfs@vger.kernel.org ]
>
> On Mon, Aug 19, 2024 at 03:15:28PM +0300, andrii.polianytsia@globallogic.com wrote:
> > Add NFS export support to the exFAT filesystem by implementing
> > the necessary export operations in fs/exfat/super.c. Enable
> > exFAT filesystems to be exported and accessed over NFS, enhancing
> > their utility in networked environments.
> >
> > Introduce the exfat_export_ops structure, which includes
> > functions to handle file handles and inode lookups necessary for NFS
> > operations.
>
> My memory is dim, but I think the reason that exporting exfat isn't
> supported already is because it's file handles aren't persistent.
Yes, and fat is the same but it supports nfs.
They seem to want to support it even considering the -ESTALE result by eviction.
This patch seems to refer to /fs/fat/nfs.c code which has the same issue.
>
> NFS requires that file handles remain the same across server
> restarts or umount/mount cycles of the exported file system.
>
>
> > Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
> > Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
> > ---
> >  fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 65 insertions(+)
> >
> > diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> > index 323ecebe6f0e..cb6dcafc3007 100644
> > --- a/fs/exfat/super.c
> > +++ b/fs/exfat/super.c
> > @@ -18,6 +18,7 @@
> >  #include <linux/nls.h>
> >  #include <linux/buffer_head.h>
> >  #include <linux/magic.h>
> > +#include <linux/exportfs.h>
> >
> >  #include "exfat_raw.h"
> >  #include "exfat_fs.h"
> > @@ -195,6 +196,69 @@ static const struct super_operations exfat_sops = {
> >       .show_options   = exfat_show_options,
> >  };
> >
> > +/**
> > + * exfat_export_get_inode - Get inode for export operations
> > + * @sb: Superblock pointer
> > + * @ino: Inode number
> > + * @generation: Generation number
> > + *
> > + * Returns pointer to inode or error pointer in case of an error.
> > + */
> > +static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
> > +     u32 generation)
> > +{
> > +     struct inode *inode = NULL;
> > +
> > +     if (ino == 0)
> > +             return ERR_PTR(-ESTALE);
> > +
> > +     inode = ilookup(sb, ino);
> > +     if (inode && generation && inode->i_generation != generation) {
> > +             iput(inode);
> > +             return ERR_PTR(-ESTALE);
> > +     }
> > +
> > +     return inode;
> > +}
> > +
> > +/**
> > + * exfat_fh_to_dentry - Convert file handle to dentry
> > + * @sb: Superblock pointer
> > + * @fid: File identifier
> > + * @fh_len: Length of the file handle
> > + * @fh_type: Type of the file handle
> > + *
> > + * Returns dentry corresponding to the file handle.
> > + */
> > +static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
> > +     struct fid *fid, int fh_len, int fh_type)
> > +{
> > +     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> > +             exfat_export_get_inode);
> > +}
> > +
> > +/**
> > + * exfat_fh_to_parent - Convert file handle to parent dentry
> > + * @sb: Superblock pointer
> > + * @fid: File identifier
> > + * @fh_len: Length of the file handle
> > + * @fh_type: Type of the file handle
> > + *
> > + * Returns parent dentry corresponding to the file handle.
> > + */
> > +static struct dentry *exfat_fh_to_parent(struct super_block *sb,
> > +     struct fid *fid, int fh_len, int fh_type)
> > +{
> > +     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> > +             exfat_export_get_inode);
> > +}
> > +
> > +static const struct export_operations exfat_export_ops = {
> > +     .encode_fh = generic_encode_ino32_fh,
> > +     .fh_to_dentry = exfat_fh_to_dentry,
> > +     .fh_to_parent = exfat_fh_to_parent,
> > +};
> > +
> >  enum {
> >       Opt_uid,
> >       Opt_gid,
> > @@ -633,6 +697,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
> >       sb->s_flags |= SB_NODIRATIME;
> >       sb->s_magic = EXFAT_SUPER_MAGIC;
> >       sb->s_op = &exfat_sops;
> > +     sb->s_export_op = &exfat_export_ops;
> >
> >       sb->s_time_gran = 10 * NSEC_PER_MSEC;
> >       sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
> > --
> > 2.25.1
> >
> >
>
> --
> Chuck Lever
Chuck Lever Aug. 19, 2024, 2:40 p.m. UTC | #3
On Mon, Aug 19, 2024 at 11:21:05PM +0900, Namjae Jeon wrote:
> >
> > [ ... adding linux-nfs@vger.kernel.org ]
> >
> > On Mon, Aug 19, 2024 at 03:15:28PM +0300, andrii.polianytsia@globallogic.com wrote:
> > > Add NFS export support to the exFAT filesystem by implementing
> > > the necessary export operations in fs/exfat/super.c. Enable
> > > exFAT filesystems to be exported and accessed over NFS, enhancing
> > > their utility in networked environments.
> > >
> > > Introduce the exfat_export_ops structure, which includes
> > > functions to handle file handles and inode lookups necessary for NFS
> > > operations.
> >
> > My memory is dim, but I think the reason that exporting exfat isn't
> > supported already is because it's file handles aren't persistent.
> Yes, and fat is the same but it supports nfs.
> They seem to want to support it even considering the -ESTALE result by eviction.
> This patch seems to refer to /fs/fat/nfs.c code which has the same issue.

Fair enough. I don't see a reference to fs/fat/nfs.c, so may I
request that this added context be included in the patch description
before this patch is merged?

Out of curiosity, is any CI testing done on fat exported via NFS? At
the moment I don't happen to include it in NFSD's CI matrix.


> > NFS requires that file handles remain the same across server
> > restarts or umount/mount cycles of the exported file system.
> >
> >
> > > Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
> > > Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
> > > ---
> > >  fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 65 insertions(+)
> > >
> > > diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> > > index 323ecebe6f0e..cb6dcafc3007 100644
> > > --- a/fs/exfat/super.c
> > > +++ b/fs/exfat/super.c
> > > @@ -18,6 +18,7 @@
> > >  #include <linux/nls.h>
> > >  #include <linux/buffer_head.h>
> > >  #include <linux/magic.h>
> > > +#include <linux/exportfs.h>
> > >
> > >  #include "exfat_raw.h"
> > >  #include "exfat_fs.h"
> > > @@ -195,6 +196,69 @@ static const struct super_operations exfat_sops = {
> > >       .show_options   = exfat_show_options,
> > >  };
> > >
> > > +/**
> > > + * exfat_export_get_inode - Get inode for export operations
> > > + * @sb: Superblock pointer
> > > + * @ino: Inode number
> > > + * @generation: Generation number
> > > + *
> > > + * Returns pointer to inode or error pointer in case of an error.
> > > + */
> > > +static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
> > > +     u32 generation)
> > > +{
> > > +     struct inode *inode = NULL;
> > > +
> > > +     if (ino == 0)
> > > +             return ERR_PTR(-ESTALE);
> > > +
> > > +     inode = ilookup(sb, ino);
> > > +     if (inode && generation && inode->i_generation != generation) {
> > > +             iput(inode);
> > > +             return ERR_PTR(-ESTALE);
> > > +     }
> > > +
> > > +     return inode;
> > > +}
> > > +
> > > +/**
> > > + * exfat_fh_to_dentry - Convert file handle to dentry
> > > + * @sb: Superblock pointer
> > > + * @fid: File identifier
> > > + * @fh_len: Length of the file handle
> > > + * @fh_type: Type of the file handle
> > > + *
> > > + * Returns dentry corresponding to the file handle.
> > > + */
> > > +static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
> > > +     struct fid *fid, int fh_len, int fh_type)
> > > +{
> > > +     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> > > +             exfat_export_get_inode);
> > > +}
> > > +
> > > +/**
> > > + * exfat_fh_to_parent - Convert file handle to parent dentry
> > > + * @sb: Superblock pointer
> > > + * @fid: File identifier
> > > + * @fh_len: Length of the file handle
> > > + * @fh_type: Type of the file handle
> > > + *
> > > + * Returns parent dentry corresponding to the file handle.
> > > + */
> > > +static struct dentry *exfat_fh_to_parent(struct super_block *sb,
> > > +     struct fid *fid, int fh_len, int fh_type)
> > > +{
> > > +     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> > > +             exfat_export_get_inode);
> > > +}
> > > +
> > > +static const struct export_operations exfat_export_ops = {
> > > +     .encode_fh = generic_encode_ino32_fh,
> > > +     .fh_to_dentry = exfat_fh_to_dentry,
> > > +     .fh_to_parent = exfat_fh_to_parent,
> > > +};
> > > +
> > >  enum {
> > >       Opt_uid,
> > >       Opt_gid,
> > > @@ -633,6 +697,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
> > >       sb->s_flags |= SB_NODIRATIME;
> > >       sb->s_magic = EXFAT_SUPER_MAGIC;
> > >       sb->s_op = &exfat_sops;
> > > +     sb->s_export_op = &exfat_export_ops;
> > >
> > >       sb->s_time_gran = 10 * NSEC_PER_MSEC;
> > >       sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
> > > --
> > > 2.25.1
> > >
> > >
> >
> > --
> > Chuck Lever
Sergii Boryshchenko Aug. 19, 2024, 4:25 p.m. UTC | #4
Hi Chuck and Namjae,
Thank you for your valuable feedback.

We will update the patch description to reference fs/fat/nfs.c, as the
implementation of exFAT NFS export is indeed based on similar logic
used in FAT, which also manages non-persistent file handles.

Before submitting this patch, we conducted extensive testing in four 
categories:
functionality, stress, stability, and performance. We did encounter some 
issues
related to limitations, such as Unix file permissions and timestamp 
granularity,
which are inherent due to exFAT's origins in Windows. However, our tests 
didn't
reveal issues related to file handle persistence. If you have any 
insights or scenarios
where this issue could be reproduced in real-world use, we would greatly 
appreciate
your guidance.

We will make the necessary comment updates and resubmit the patch shortly.

--
Sergii Boryshchenko

On 19.08.24 17:40, Chuck Lever wrote:
> On Mon, Aug 19, 2024 at 11:21:05PM +0900, Namjae Jeon wrote:
>>> [ ... adding linux-nfs@vger.kernel.org ]
>>>
>>> On Mon, Aug 19, 2024 at 03:15:28PM +0300, andrii.polianytsia@globallogic.com wrote:
>>>> Add NFS export support to the exFAT filesystem by implementing
>>>> the necessary export operations in fs/exfat/super.c. Enable
>>>> exFAT filesystems to be exported and accessed over NFS, enhancing
>>>> their utility in networked environments.
>>>>
>>>> Introduce the exfat_export_ops structure, which includes
>>>> functions to handle file handles and inode lookups necessary for NFS
>>>> operations.
>>> My memory is dim, but I think the reason that exporting exfat isn't
>>> supported already is because it's file handles aren't persistent.
>> Yes, and fat is the same but it supports nfs.
>> They seem to want to support it even considering the -ESTALE result by eviction.
>> This patch seems to refer to /fs/fat/nfs.c code which has the same issue.
> Fair enough. I don't see a reference to fs/fat/nfs.c, so may I
> request that this added context be included in the patch description
> before this patch is merged?
>
> Out of curiosity, is any CI testing done on fat exported via NFS? At
> the moment I don't happen to include it in NFSD's CI matrix.
>
>
>>> NFS requires that file handles remain the same across server
>>> restarts or umount/mount cycles of the exported file system.
>>>
>>>
>>>> Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
>>>> Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
>>>> ---
>>>>   fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>   1 file changed, 65 insertions(+)
>>>>
>>>> diff --git a/fs/exfat/super.c b/fs/exfat/super.c
>>>> index 323ecebe6f0e..cb6dcafc3007 100644
>>>> --- a/fs/exfat/super.c
>>>> +++ b/fs/exfat/super.c
>>>> @@ -18,6 +18,7 @@
>>>>   #include <linux/nls.h>
>>>>   #include <linux/buffer_head.h>
>>>>   #include <linux/magic.h>
>>>> +#include <linux/exportfs.h>
>>>>
>>>>   #include "exfat_raw.h"
>>>>   #include "exfat_fs.h"
>>>> @@ -195,6 +196,69 @@ static const struct super_operations exfat_sops = {
>>>>        .show_options   = exfat_show_options,
>>>>   };
>>>>
>>>> +/**
>>>> + * exfat_export_get_inode - Get inode for export operations
>>>> + * @sb: Superblock pointer
>>>> + * @ino: Inode number
>>>> + * @generation: Generation number
>>>> + *
>>>> + * Returns pointer to inode or error pointer in case of an error.
>>>> + */
>>>> +static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
>>>> +     u32 generation)
>>>> +{
>>>> +     struct inode *inode = NULL;
>>>> +
>>>> +     if (ino == 0)
>>>> +             return ERR_PTR(-ESTALE);
>>>> +
>>>> +     inode = ilookup(sb, ino);
>>>> +     if (inode && generation && inode->i_generation != generation) {
>>>> +             iput(inode);
>>>> +             return ERR_PTR(-ESTALE);
>>>> +     }
>>>> +
>>>> +     return inode;
>>>> +}
>>>> +
>>>> +/**
>>>> + * exfat_fh_to_dentry - Convert file handle to dentry
>>>> + * @sb: Superblock pointer
>>>> + * @fid: File identifier
>>>> + * @fh_len: Length of the file handle
>>>> + * @fh_type: Type of the file handle
>>>> + *
>>>> + * Returns dentry corresponding to the file handle.
>>>> + */
>>>> +static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
>>>> +     struct fid *fid, int fh_len, int fh_type)
>>>> +{
>>>> +     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
>>>> +             exfat_export_get_inode);
>>>> +}
>>>> +
>>>> +/**
>>>> + * exfat_fh_to_parent - Convert file handle to parent dentry
>>>> + * @sb: Superblock pointer
>>>> + * @fid: File identifier
>>>> + * @fh_len: Length of the file handle
>>>> + * @fh_type: Type of the file handle
>>>> + *
>>>> + * Returns parent dentry corresponding to the file handle.
>>>> + */
>>>> +static struct dentry *exfat_fh_to_parent(struct super_block *sb,
>>>> +     struct fid *fid, int fh_len, int fh_type)
>>>> +{
>>>> +     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
>>>> +             exfat_export_get_inode);
>>>> +}
>>>> +
>>>> +static const struct export_operations exfat_export_ops = {
>>>> +     .encode_fh = generic_encode_ino32_fh,
>>>> +     .fh_to_dentry = exfat_fh_to_dentry,
>>>> +     .fh_to_parent = exfat_fh_to_parent,
>>>> +};
>>>> +
>>>>   enum {
>>>>        Opt_uid,
>>>>        Opt_gid,
>>>> @@ -633,6 +697,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
>>>>        sb->s_flags |= SB_NODIRATIME;
>>>>        sb->s_magic = EXFAT_SUPER_MAGIC;
>>>>        sb->s_op = &exfat_sops;
>>>> +     sb->s_export_op = &exfat_export_ops;
>>>>
>>>>        sb->s_time_gran = 10 * NSEC_PER_MSEC;
>>>>        sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
>>>> --
>>>> 2.25.1
>>>>
>>>>
>>> --
>>> Chuck Lever
Namjae Jeon Aug. 19, 2024, 11:41 p.m. UTC | #5
On Mon, Aug 19, 2024 at 11:40 PM Chuck Lever <chuck.lever@oracle.com> wrote:
>
> On Mon, Aug 19, 2024 at 11:21:05PM +0900, Namjae Jeon wrote:
> > >
> > > [ ... adding linux-nfs@vger.kernel.org ]
> > >
> > > On Mon, Aug 19, 2024 at 03:15:28PM +0300, andrii.polianytsia@globallogic.com wrote:
> > > > Add NFS export support to the exFAT filesystem by implementing
> > > > the necessary export operations in fs/exfat/super.c. Enable
> > > > exFAT filesystems to be exported and accessed over NFS, enhancing
> > > > their utility in networked environments.
> > > >
> > > > Introduce the exfat_export_ops structure, which includes
> > > > functions to handle file handles and inode lookups necessary for NFS
> > > > operations.
> > >
> > > My memory is dim, but I think the reason that exporting exfat isn't
> > > supported already is because it's file handles aren't persistent.
> > Yes, and fat is the same but it supports nfs.
> > They seem to want to support it even considering the -ESTALE result by eviction.
> > This patch seems to refer to /fs/fat/nfs.c code which has the same issue.
>
> Fair enough. I don't see a reference to fs/fat/nfs.c, so may I
> request that this added context be included in the patch description
> before this patch is merged?
Sure, I haven't decided yet whether to accept this patch.
I'll look into it more and decide.
>
> Out of curiosity, is any CI testing done on fat exported via NFS? At
> the moment I don't happen to include it in NFSD's CI matrix.
I don't maintain fat-fs, so I'm not sure if it's been verified with
some CI test.
However, if exfat support NFS export, I'll verify it with that test.
>
>
> > > NFS requires that file handles remain the same across server
> > > restarts or umount/mount cycles of the exported file system.
> > >
> > >
> > > > Signed-off-by: Sergii Boryshchenko <sergii.boryshchenko@globallogic.com>
> > > > Signed-off-by: Andrii Polianytsia <andrii.polianytsia@globallogic.com>
> > > > ---
> > > >  fs/exfat/super.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
> > > >  1 file changed, 65 insertions(+)
> > > >
> > > > diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> > > > index 323ecebe6f0e..cb6dcafc3007 100644
> > > > --- a/fs/exfat/super.c
> > > > +++ b/fs/exfat/super.c
> > > > @@ -18,6 +18,7 @@
> > > >  #include <linux/nls.h>
> > > >  #include <linux/buffer_head.h>
> > > >  #include <linux/magic.h>
> > > > +#include <linux/exportfs.h>
> > > >
> > > >  #include "exfat_raw.h"
> > > >  #include "exfat_fs.h"
> > > > @@ -195,6 +196,69 @@ static const struct super_operations exfat_sops = {
> > > >       .show_options   = exfat_show_options,
> > > >  };
> > > >
> > > > +/**
> > > > + * exfat_export_get_inode - Get inode for export operations
> > > > + * @sb: Superblock pointer
> > > > + * @ino: Inode number
> > > > + * @generation: Generation number
> > > > + *
> > > > + * Returns pointer to inode or error pointer in case of an error.
> > > > + */
> > > > +static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
> > > > +     u32 generation)
> > > > +{
> > > > +     struct inode *inode = NULL;
> > > > +
> > > > +     if (ino == 0)
> > > > +             return ERR_PTR(-ESTALE);
> > > > +
> > > > +     inode = ilookup(sb, ino);
> > > > +     if (inode && generation && inode->i_generation != generation) {
> > > > +             iput(inode);
> > > > +             return ERR_PTR(-ESTALE);
> > > > +     }
> > > > +
> > > > +     return inode;
> > > > +}
> > > > +
> > > > +/**
> > > > + * exfat_fh_to_dentry - Convert file handle to dentry
> > > > + * @sb: Superblock pointer
> > > > + * @fid: File identifier
> > > > + * @fh_len: Length of the file handle
> > > > + * @fh_type: Type of the file handle
> > > > + *
> > > > + * Returns dentry corresponding to the file handle.
> > > > + */
> > > > +static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
> > > > +     struct fid *fid, int fh_len, int fh_type)
> > > > +{
> > > > +     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> > > > +             exfat_export_get_inode);
> > > > +}
> > > > +
> > > > +/**
> > > > + * exfat_fh_to_parent - Convert file handle to parent dentry
> > > > + * @sb: Superblock pointer
> > > > + * @fid: File identifier
> > > > + * @fh_len: Length of the file handle
> > > > + * @fh_type: Type of the file handle
> > > > + *
> > > > + * Returns parent dentry corresponding to the file handle.
> > > > + */
> > > > +static struct dentry *exfat_fh_to_parent(struct super_block *sb,
> > > > +     struct fid *fid, int fh_len, int fh_type)
> > > > +{
> > > > +     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> > > > +             exfat_export_get_inode);
> > > > +}
> > > > +
> > > > +static const struct export_operations exfat_export_ops = {
> > > > +     .encode_fh = generic_encode_ino32_fh,
> > > > +     .fh_to_dentry = exfat_fh_to_dentry,
> > > > +     .fh_to_parent = exfat_fh_to_parent,
> > > > +};
> > > > +
> > > >  enum {
> > > >       Opt_uid,
> > > >       Opt_gid,
> > > > @@ -633,6 +697,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
> > > >       sb->s_flags |= SB_NODIRATIME;
> > > >       sb->s_magic = EXFAT_SUPER_MAGIC;
> > > >       sb->s_op = &exfat_sops;
> > > > +     sb->s_export_op = &exfat_export_ops;
> > > >
> > > >       sb->s_time_gran = 10 * NSEC_PER_MSEC;
> > > >       sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
> > > > --
> > > > 2.25.1
> > > >
> > > >
> > >
> > > --
> > > Chuck Lever
>
> --
> Chuck Lever
diff mbox series

Patch

diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 323ecebe6f0e..cb6dcafc3007 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -18,6 +18,7 @@ 
 #include <linux/nls.h>
 #include <linux/buffer_head.h>
 #include <linux/magic.h>
+#include <linux/exportfs.h>
 
 #include "exfat_raw.h"
 #include "exfat_fs.h"
@@ -195,6 +196,69 @@  static const struct super_operations exfat_sops = {
 	.show_options	= exfat_show_options,
 };
 
+/**
+ * exfat_export_get_inode - Get inode for export operations
+ * @sb: Superblock pointer
+ * @ino: Inode number
+ * @generation: Generation number
+ *
+ * Returns pointer to inode or error pointer in case of an error.
+ */
+static struct inode *exfat_export_get_inode(struct super_block *sb, u64 ino,
+	u32 generation)
+{
+	struct inode *inode = NULL;
+
+	if (ino == 0)
+		return ERR_PTR(-ESTALE);
+
+	inode = ilookup(sb, ino);
+	if (inode && generation && inode->i_generation != generation) {
+		iput(inode);
+		return ERR_PTR(-ESTALE);
+	}
+
+	return inode;
+}
+
+/**
+ * exfat_fh_to_dentry - Convert file handle to dentry
+ * @sb: Superblock pointer
+ * @fid: File identifier
+ * @fh_len: Length of the file handle
+ * @fh_type: Type of the file handle
+ *
+ * Returns dentry corresponding to the file handle.
+ */
+static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
+	struct fid *fid, int fh_len, int fh_type)
+{
+	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+		exfat_export_get_inode);
+}
+
+/**
+ * exfat_fh_to_parent - Convert file handle to parent dentry
+ * @sb: Superblock pointer
+ * @fid: File identifier
+ * @fh_len: Length of the file handle
+ * @fh_type: Type of the file handle
+ *
+ * Returns parent dentry corresponding to the file handle.
+ */
+static struct dentry *exfat_fh_to_parent(struct super_block *sb,
+	struct fid *fid, int fh_len, int fh_type)
+{
+	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+		exfat_export_get_inode);
+}
+
+static const struct export_operations exfat_export_ops = {
+	.encode_fh = generic_encode_ino32_fh,
+	.fh_to_dentry = exfat_fh_to_dentry,
+	.fh_to_parent = exfat_fh_to_parent,
+};
+
 enum {
 	Opt_uid,
 	Opt_gid,
@@ -633,6 +697,7 @@  static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
 	sb->s_flags |= SB_NODIRATIME;
 	sb->s_magic = EXFAT_SUPER_MAGIC;
 	sb->s_op = &exfat_sops;
+	sb->s_export_op = &exfat_export_ops;
 
 	sb->s_time_gran = 10 * NSEC_PER_MSEC;
 	sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;