* [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
@ 2020-11-30 19:38 J. Bruce Fields
2020-11-30 19:46 ` J. Bruce Fields
2020-11-30 21:03 ` Chuck Lever
0 siblings, 2 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 19:38 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
inode_query_iversion() can modify i_version. Depending on the exported
filesystem, that may not be safe. For example, if you're re-exporting
NFS, NFS stores the server's change attribute in i_version and does not
expect it to be modified locally. This has been observed causing
unnecessary cache invalidations.
The way a filesystem indicates that it's OK to call
inode_query_iverson() is by setting SB_I_VERSION.
So, move the I_VERSION check out of encode_change(), where it's used
only in FATTR responses, to nfsd4_changeattr(), which is also called for
pre- and post- operation attributes.
(Note we could also pull the NFSEXP_V4ROOT case into
nfsd4_change_attribute as well. That would actually be a no-op, since
pre/post attrs are only used for metadata-modifying operations, and
V4ROOT exports are read-only. But we might make the change in the
future just for simplicity.)
Reported-by: Daire Byrne <daire@dneg.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs3xdr.c | 5 ++---
fs/nfsd/nfs4xdr.c | 6 +-----
fs/nfsd/nfsfh.h | 14 ++++++++++----
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 2277f83da250..dfbf390ff40c 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
printk("nfsd: inode locked twice during operation.\n");
err = fh_getattr(fhp, &fhp->fh_post_attr);
- fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
- d_inode(fhp->fh_dentry));
if (err) {
fhp->fh_post_saved = false;
- /* Grab the ctime anyway - set_change_info might use it */
fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
} else
fhp->fh_post_saved = true;
+ fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
+ d_inode(fhp->fh_dentry));
}
/*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 833a2c64dfe8..56fd5f6d5c44 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
if (exp->ex_flags & NFSEXP_V4ROOT) {
*p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
*p++ = 0;
- } else if (IS_I_VERSION(inode)) {
+ } else
p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
- } else {
- *p++ = cpu_to_be32(stat->ctime.tv_sec);
- *p++ = cpu_to_be32(stat->ctime.tv_nsec);
- }
return p;
}
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 56cfbc361561..3faf5974fa4e 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
{
u64 chattr;
- chattr = stat->ctime.tv_sec;
- chattr <<= 30;
- chattr += stat->ctime.tv_nsec;
- chattr += inode_query_iversion(inode);
+ if (IS_I_VERSION(inode)) {
+ chattr = stat->ctime.tv_sec;
+ chattr <<= 30;
+ chattr += stat->ctime.tv_nsec;
+ chattr += inode_query_iversion(inode);
+ } else {
+ chattr = cpu_to_be32(stat->ctime.tv_sec);
+ chattr <<= 32;
+ chattr += cpu_to_be32(stat->ctime.tv_nsec);
+ }
return chattr;
}
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-11-30 19:38 J. Bruce Fields
@ 2020-11-30 19:46 ` J. Bruce Fields
2020-11-30 21:03 ` Chuck Lever
1 sibling, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 19:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
This patch fixes the bug Daire saw. The rest is a replacement for the
series I sent before, except that I haven't included the last few
patches, which will need review from other filesystem people.
--b.
On Mon, Nov 30, 2020 at 02:38:53PM -0500, J. Bruce Fields wrote:
> From: "J. Bruce Fields" <bfields@redhat.com>
>
> inode_query_iversion() can modify i_version. Depending on the exported
> filesystem, that may not be safe. For example, if you're re-exporting
> NFS, NFS stores the server's change attribute in i_version and does not
> expect it to be modified locally. This has been observed causing
> unnecessary cache invalidations.
>
> The way a filesystem indicates that it's OK to call
> inode_query_iverson() is by setting SB_I_VERSION.
>
> So, move the I_VERSION check out of encode_change(), where it's used
> only in FATTR responses, to nfsd4_changeattr(), which is also called for
> pre- and post- operation attributes.
>
> (Note we could also pull the NFSEXP_V4ROOT case into
> nfsd4_change_attribute as well. That would actually be a no-op, since
> pre/post attrs are only used for metadata-modifying operations, and
> V4ROOT exports are read-only. But we might make the change in the
> future just for simplicity.)
>
> Reported-by: Daire Byrne <daire@dneg.com>
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/nfsd/nfs3xdr.c | 5 ++---
> fs/nfsd/nfs4xdr.c | 6 +-----
> fs/nfsd/nfsfh.h | 14 ++++++++++----
> 3 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index 2277f83da250..dfbf390ff40c 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> printk("nfsd: inode locked twice during operation.\n");
>
> err = fh_getattr(fhp, &fhp->fh_post_attr);
> - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> - d_inode(fhp->fh_dentry));
> if (err) {
> fhp->fh_post_saved = false;
> - /* Grab the ctime anyway - set_change_info might use it */
> fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> } else
> fhp->fh_post_saved = true;
> + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> + d_inode(fhp->fh_dentry));
> }
>
> /*
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 833a2c64dfe8..56fd5f6d5c44 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> if (exp->ex_flags & NFSEXP_V4ROOT) {
> *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> *p++ = 0;
> - } else if (IS_I_VERSION(inode)) {
> + } else
> p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> - } else {
> - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> - }
> return p;
> }
>
> diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> index 56cfbc361561..3faf5974fa4e 100644
> --- a/fs/nfsd/nfsfh.h
> +++ b/fs/nfsd/nfsfh.h
> @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> {
> u64 chattr;
>
> - chattr = stat->ctime.tv_sec;
> - chattr <<= 30;
> - chattr += stat->ctime.tv_nsec;
> - chattr += inode_query_iversion(inode);
> + if (IS_I_VERSION(inode)) {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 30;
> + chattr += stat->ctime.tv_nsec;
> + chattr += inode_query_iversion(inode);
> + } else {
> + chattr = cpu_to_be32(stat->ctime.tv_sec);
> + chattr <<= 32;
> + chattr += cpu_to_be32(stat->ctime.tv_nsec);
> + }
> return chattr;
> }
>
> --
> 2.28.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-11-30 19:38 J. Bruce Fields
2020-11-30 19:46 ` J. Bruce Fields
@ 2020-11-30 21:03 ` Chuck Lever
2020-11-30 21:42 ` Bruce Fields
1 sibling, 1 reply; 14+ messages in thread
From: Chuck Lever @ 2020-11-30 21:03 UTC (permalink / raw)
To: Bruce Fields; +Cc: Linux NFS Mailing List, Bruce Fields
> On Nov 30, 2020, at 2:38 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
>
> From: "J. Bruce Fields" <bfields@redhat.com>
>
> inode_query_iversion() can modify i_version. Depending on the exported
> filesystem, that may not be safe. For example, if you're re-exporting
> NFS, NFS stores the server's change attribute in i_version and does not
> expect it to be modified locally. This has been observed causing
> unnecessary cache invalidations.
>
> The way a filesystem indicates that it's OK to call
> inode_query_iverson() is by setting SB_I_VERSION.
>
> So, move the I_VERSION check out of encode_change(), where it's used
> only in FATTR responses, to nfsd4_changeattr(), which is also called for
> pre- and post- operation attributes.
>
> (Note we could also pull the NFSEXP_V4ROOT case into
> nfsd4_change_attribute as well. That would actually be a no-op, since
> pre/post attrs are only used for metadata-modifying operations, and
> V4ROOT exports are read-only. But we might make the change in the
> future just for simplicity.)
>
> Reported-by: Daire Byrne <daire@dneg.com>
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
New sparse warnings after this one is applied:
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: warning: incorrect type in assignment (different base types)
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: expected unsigned long long [assigned] [usertype] chattr
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: got restricted __be32 [usertype]
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: warning: invalid assignment: +=
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: left side has type unsigned long long
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: right side has type restricted __be32
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: warning: incorrect type in assignment (different base types)
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: expected unsigned long long [assigned] [usertype] chattr
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: got restricted __be32 [usertype]
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: warning: invalid assignment: +=
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: left side has type unsigned long long
/home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: right side has type restricted __be32
> ---
> fs/nfsd/nfs3xdr.c | 5 ++---
> fs/nfsd/nfs4xdr.c | 6 +-----
> fs/nfsd/nfsfh.h | 14 ++++++++++----
> 3 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index 2277f83da250..dfbf390ff40c 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> printk("nfsd: inode locked twice during operation.\n");
>
> err = fh_getattr(fhp, &fhp->fh_post_attr);
> - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> - d_inode(fhp->fh_dentry));
> if (err) {
> fhp->fh_post_saved = false;
> - /* Grab the ctime anyway - set_change_info might use it */
> fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> } else
> fhp->fh_post_saved = true;
> + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> + d_inode(fhp->fh_dentry));
> }
>
> /*
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 833a2c64dfe8..56fd5f6d5c44 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> if (exp->ex_flags & NFSEXP_V4ROOT) {
> *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> *p++ = 0;
> - } else if (IS_I_VERSION(inode)) {
> + } else
> p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> - } else {
> - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> - }
> return p;
> }
>
> diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> index 56cfbc361561..3faf5974fa4e 100644
> --- a/fs/nfsd/nfsfh.h
> +++ b/fs/nfsd/nfsfh.h
> @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> {
> u64 chattr;
>
> - chattr = stat->ctime.tv_sec;
> - chattr <<= 30;
> - chattr += stat->ctime.tv_nsec;
> - chattr += inode_query_iversion(inode);
> + if (IS_I_VERSION(inode)) {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 30;
> + chattr += stat->ctime.tv_nsec;
> + chattr += inode_query_iversion(inode);
> + } else {
> + chattr = cpu_to_be32(stat->ctime.tv_sec);
> + chattr <<= 32;
> + chattr += cpu_to_be32(stat->ctime.tv_nsec);
> + }
> return chattr;
> }
>
> --
> 2.28.0
>
--
Chuck Lever
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-11-30 21:03 ` Chuck Lever
@ 2020-11-30 21:42 ` Bruce Fields
0 siblings, 0 replies; 14+ messages in thread
From: Bruce Fields @ 2020-11-30 21:42 UTC (permalink / raw)
To: Chuck Lever; +Cc: Linux NFS Mailing List, Bruce Fields
On Mon, Nov 30, 2020 at 04:03:23PM -0500, Chuck Lever wrote:
>
>
> > On Nov 30, 2020, at 2:38 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > From: "J. Bruce Fields" <bfields@redhat.com>
> >
> > inode_query_iversion() can modify i_version. Depending on the exported
> > filesystem, that may not be safe. For example, if you're re-exporting
> > NFS, NFS stores the server's change attribute in i_version and does not
> > expect it to be modified locally. This has been observed causing
> > unnecessary cache invalidations.
> >
> > The way a filesystem indicates that it's OK to call
> > inode_query_iverson() is by setting SB_I_VERSION.
> >
> > So, move the I_VERSION check out of encode_change(), where it's used
> > only in FATTR responses, to nfsd4_changeattr(), which is also called for
> > pre- and post- operation attributes.
> >
> > (Note we could also pull the NFSEXP_V4ROOT case into
> > nfsd4_change_attribute as well. That would actually be a no-op, since
> > pre/post attrs are only used for metadata-modifying operations, and
> > V4ROOT exports are read-only. But we might make the change in the
> > future just for simplicity.)
> >
> > Reported-by: Daire Byrne <daire@dneg.com>
> > Signed-off-by: J. Bruce Fields <bfields@redhat.com>
>
> New sparse warnings after this one is applied:
D'oh. I'll send again, thanks!
--b.
>
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: warning: incorrect type in assignment (different base types)
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: expected unsigned long long [assigned] [usertype] chattr
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: got restricted __be32 [usertype]
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: warning: invalid assignment: +=
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: left side has type unsigned long long
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: right side has type restricted __be32
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: warning: incorrect type in assignment (different base types)
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: expected unsigned long long [assigned] [usertype] chattr
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:270:24: got restricted __be32 [usertype]
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: warning: invalid assignment: +=
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: left side has type unsigned long long
> /home/cel/src/linux/linux/fs/nfsd/nfsfh.h:272:24: right side has type restricted __be32
>
>
> > ---
> > fs/nfsd/nfs3xdr.c | 5 ++---
> > fs/nfsd/nfs4xdr.c | 6 +-----
> > fs/nfsd/nfsfh.h | 14 ++++++++++----
> > 3 files changed, 13 insertions(+), 12 deletions(-)
> >
> > diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> > index 2277f83da250..dfbf390ff40c 100644
> > --- a/fs/nfsd/nfs3xdr.c
> > +++ b/fs/nfsd/nfs3xdr.c
> > @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> > printk("nfsd: inode locked twice during operation.\n");
> >
> > err = fh_getattr(fhp, &fhp->fh_post_attr);
> > - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> > - d_inode(fhp->fh_dentry));
> > if (err) {
> > fhp->fh_post_saved = false;
> > - /* Grab the ctime anyway - set_change_info might use it */
> > fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> > } else
> > fhp->fh_post_saved = true;
> > + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> > + d_inode(fhp->fh_dentry));
> > }
> >
> > /*
> > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > index 833a2c64dfe8..56fd5f6d5c44 100644
> > --- a/fs/nfsd/nfs4xdr.c
> > +++ b/fs/nfsd/nfs4xdr.c
> > @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> > if (exp->ex_flags & NFSEXP_V4ROOT) {
> > *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> > *p++ = 0;
> > - } else if (IS_I_VERSION(inode)) {
> > + } else
> > p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> > - } else {
> > - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> > - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> > - }
> > return p;
> > }
> >
> > diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> > index 56cfbc361561..3faf5974fa4e 100644
> > --- a/fs/nfsd/nfsfh.h
> > +++ b/fs/nfsd/nfsfh.h
> > @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> > {
> > u64 chattr;
> >
> > - chattr = stat->ctime.tv_sec;
> > - chattr <<= 30;
> > - chattr += stat->ctime.tv_nsec;
> > - chattr += inode_query_iversion(inode);
> > + if (IS_I_VERSION(inode)) {
> > + chattr = stat->ctime.tv_sec;
> > + chattr <<= 30;
> > + chattr += stat->ctime.tv_nsec;
> > + chattr += inode_query_iversion(inode);
> > + } else {
> > + chattr = cpu_to_be32(stat->ctime.tv_sec);
> > + chattr <<= 32;
> > + chattr += cpu_to_be32(stat->ctime.tv_nsec);
> > + }
> > return chattr;
> > }
> >
> > --
> > 2.28.0
> >
>
> --
> Chuck Lever
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
@ 2020-11-30 22:46 J. Bruce Fields
2020-11-30 22:46 ` [PATCH 2/5] nfsd: simplify nfsd4_change_info J. Bruce Fields
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 22:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
inode_query_iversion() can modify i_version. Depending on the exported
filesystem, that may not be safe. For example, if you're re-exporting
NFS, NFS stores the server's change attribute in i_version and does not
expect it to be modified locally. This has been observed causing
unnecessary cache invalidations.
The way a filesystem indicates that it's OK to call
inode_query_iverson() is by setting SB_I_VERSION.
So, move the I_VERSION check out of encode_change(), where it's used
only in FATTR responses, to nfsd4_changeattr(), which is also called for
pre- and post- operation attributes.
(Note we could also pull the NFSEXP_V4ROOT case into
nfsd4_change_attribute as well. That would actually be a no-op, since
pre/post attrs are only used for metadata-modifying operations, and
V4ROOT exports are read-only. But we might make the change in the
future just for simplicity.)
Reported-by: Daire Byrne <daire@dneg.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs3xdr.c | 5 ++---
fs/nfsd/nfs4xdr.c | 6 +-----
fs/nfsd/nfsfh.h | 14 ++++++++++----
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 2277f83da250..dfbf390ff40c 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
printk("nfsd: inode locked twice during operation.\n");
err = fh_getattr(fhp, &fhp->fh_post_attr);
- fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
- d_inode(fhp->fh_dentry));
if (err) {
fhp->fh_post_saved = false;
- /* Grab the ctime anyway - set_change_info might use it */
fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
} else
fhp->fh_post_saved = true;
+ fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
+ d_inode(fhp->fh_dentry));
}
/*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 833a2c64dfe8..56fd5f6d5c44 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
if (exp->ex_flags & NFSEXP_V4ROOT) {
*p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
*p++ = 0;
- } else if (IS_I_VERSION(inode)) {
+ } else
p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
- } else {
- *p++ = cpu_to_be32(stat->ctime.tv_sec);
- *p++ = cpu_to_be32(stat->ctime.tv_nsec);
- }
return p;
}
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 56cfbc361561..39d764b129fa 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
{
u64 chattr;
- chattr = stat->ctime.tv_sec;
- chattr <<= 30;
- chattr += stat->ctime.tv_nsec;
- chattr += inode_query_iversion(inode);
+ if (IS_I_VERSION(inode)) {
+ chattr = stat->ctime.tv_sec;
+ chattr <<= 30;
+ chattr += stat->ctime.tv_nsec;
+ chattr += inode_query_iversion(inode);
+ } else {
+ chattr = stat->ctime.tv_sec;
+ chattr <<= 32;
+ chattr += stat->ctime.tv_nsec;
+ }
return chattr;
}
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/5] nfsd: simplify nfsd4_change_info
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
@ 2020-11-30 22:46 ` J. Bruce Fields
2020-11-30 22:46 ` [PATCH 3/5] nfsd: minor nfsd4_change_attribute cleanup J. Bruce Fields
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 22:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
It doesn't make sense to carry all these extra fields around. Just
make everything into change attribute from the start.
This is just cleanup, there should be no change in behavior.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4xdr.c | 11 ++---------
fs/nfsd/xdr4.h | 11 -----------
2 files changed, 2 insertions(+), 20 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 56fd5f6d5c44..18c912930947 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2331,15 +2331,8 @@ static __be32 *encode_time_delta(__be32 *p, struct inode *inode)
static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c)
{
*p++ = cpu_to_be32(c->atomic);
- if (c->change_supported) {
- p = xdr_encode_hyper(p, c->before_change);
- p = xdr_encode_hyper(p, c->after_change);
- } else {
- *p++ = cpu_to_be32(c->before_ctime_sec);
- *p++ = cpu_to_be32(c->before_ctime_nsec);
- *p++ = cpu_to_be32(c->after_ctime_sec);
- *p++ = cpu_to_be32(c->after_ctime_nsec);
- }
+ p = xdr_encode_hyper(p, c->before_change);
+ p = xdr_encode_hyper(p, c->after_change);
return p;
}
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 679d40af1bbb..3a59053084e6 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -76,12 +76,7 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
struct nfsd4_change_info {
u32 atomic;
- bool change_supported;
- u32 before_ctime_sec;
- u32 before_ctime_nsec;
u64 before_change;
- u32 after_ctime_sec;
- u32 after_ctime_nsec;
u64 after_change;
};
@@ -768,15 +763,9 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
{
BUG_ON(!fhp->fh_pre_saved);
cinfo->atomic = (u32)fhp->fh_post_saved;
- cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry));
cinfo->before_change = fhp->fh_pre_change;
cinfo->after_change = fhp->fh_post_change;
- cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
- cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
- cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
- cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
-
}
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/5] nfsd: minor nfsd4_change_attribute cleanup
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
2020-11-30 22:46 ` [PATCH 2/5] nfsd: simplify nfsd4_change_info J. Bruce Fields
@ 2020-11-30 22:46 ` J. Bruce Fields
2020-11-30 22:46 ` [PATCH 4/5] nfsd4: don't query change attribute in v2/v3 case J. Bruce Fields
` (3 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 22:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
Minor cleanup, no change in behavior.
Also pull out a common helper that'll be useful elsewhere.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfsfh.h | 13 +++++--------
include/linux/iversion.h | 13 +++++++++++++
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 39d764b129fa..45bd776290d5 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -259,19 +259,16 @@ fh_clear_wcc(struct svc_fh *fhp)
static inline u64 nfsd4_change_attribute(struct kstat *stat,
struct inode *inode)
{
- u64 chattr;
-
if (IS_I_VERSION(inode)) {
+ u64 chattr;
+
chattr = stat->ctime.tv_sec;
chattr <<= 30;
chattr += stat->ctime.tv_nsec;
chattr += inode_query_iversion(inode);
- } else {
- chattr = stat->ctime.tv_sec;
- chattr <<= 32;
- chattr += stat->ctime.tv_nsec;
- }
- return chattr;
+ return chattr;
+ } else
+ return time_to_chattr(&stat->ctime);
}
extern void fill_pre_wcc(struct svc_fh *fhp);
diff --git a/include/linux/iversion.h b/include/linux/iversion.h
index 2917ef990d43..3bfebde5a1a6 100644
--- a/include/linux/iversion.h
+++ b/include/linux/iversion.h
@@ -328,6 +328,19 @@ inode_query_iversion(struct inode *inode)
return cur >> I_VERSION_QUERIED_SHIFT;
}
+/*
+ * For filesystems without any sort of change attribute, the best we can
+ * do is fake one up from the ctime:
+ */
+static inline u64 time_to_chattr(struct timespec64 *t)
+{
+ u64 chattr = t->tv_sec;
+
+ chattr <<= 32;
+ chattr += t->tv_nsec;
+ return chattr;
+}
+
/**
* inode_eq_iversion_raw - check whether the raw i_version counter has changed
* @inode: inode to check
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/5] nfsd4: don't query change attribute in v2/v3 case
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
2020-11-30 22:46 ` [PATCH 2/5] nfsd: simplify nfsd4_change_info J. Bruce Fields
2020-11-30 22:46 ` [PATCH 3/5] nfsd: minor nfsd4_change_attribute cleanup J. Bruce Fields
@ 2020-11-30 22:46 ` J. Bruce Fields
2020-11-30 22:46 ` [PATCH 5/5] Revert "nfsd4: support change_attr_type attribute" J. Bruce Fields
` (2 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 22:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
inode_query_iversion() has side effects, and there's no point calling it
when we're not even going to use it.
We check whether we're currently processing a v4 request by checking
fh_maxsize, which is arguably a little hacky; we could add a flag to
svc_fh instead.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs3xdr.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index dfbf390ff40c..f4fd54dc6965 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -259,11 +259,11 @@ void fill_pre_wcc(struct svc_fh *fhp)
{
struct inode *inode;
struct kstat stat;
+ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
__be32 err;
if (fhp->fh_pre_saved)
return;
-
inode = d_inode(fhp->fh_dentry);
err = fh_getattr(fhp, &stat);
if (err) {
@@ -272,11 +272,12 @@ void fill_pre_wcc(struct svc_fh *fhp)
stat.ctime = inode->i_ctime;
stat.size = inode->i_size;
}
+ if (v4)
+ fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
fhp->fh_pre_mtime = stat.mtime;
fhp->fh_pre_ctime = stat.ctime;
fhp->fh_pre_size = stat.size;
- fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
fhp->fh_pre_saved = true;
}
@@ -285,6 +286,8 @@ void fill_pre_wcc(struct svc_fh *fhp)
*/
void fill_post_wcc(struct svc_fh *fhp)
{
+ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
+ struct inode *inode = d_inode(fhp->fh_dentry);
__be32 err;
if (fhp->fh_post_saved)
@@ -293,11 +296,12 @@ void fill_post_wcc(struct svc_fh *fhp)
err = fh_getattr(fhp, &fhp->fh_post_attr);
if (err) {
fhp->fh_post_saved = false;
- fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
+ fhp->fh_post_attr.ctime = inode->i_ctime;
} else
fhp->fh_post_saved = true;
- fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
- d_inode(fhp->fh_dentry));
+ if (v4)
+ fhp->fh_post_change =
+ nfsd4_change_attribute(&fhp->fh_post_attr, inode);
}
/*
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/5] Revert "nfsd4: support change_attr_type attribute"
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
` (2 preceding siblings ...)
2020-11-30 22:46 ` [PATCH 4/5] nfsd4: don't query change attribute in v2/v3 case J. Bruce Fields
@ 2020-11-30 22:46 ` J. Bruce Fields
2020-12-01 16:30 ` [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case Jeff Layton
2020-12-01 16:43 ` Jeff Layton
5 siblings, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-11-30 22:46 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@redhat.com>
This reverts commit a85857633b04d57f4524cca0a2bfaf87b2543f9f.
We're still factoring ctime into our change attribute even in the
IS_I_VERSION case. If someone sets the system time backwards, a client
could see the change attribute go backwards. Maybe we can just say
"well, don't do that", but there's some question whether that's good
enough, or whether we need a better guarantee.
Also, the client still isn't actually using the attribute.
While we're still figuring this out, let's just stop returning this
attribute.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4xdr.c | 10 ----------
fs/nfsd/nfsd.h | 1 -
include/linux/nfs4.h | 8 --------
3 files changed, 19 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 18c912930947..c33838caf8c6 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3183,16 +3183,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
goto out;
}
- if (bmval2 & FATTR4_WORD2_CHANGE_ATTR_TYPE) {
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
- if (IS_I_VERSION(d_inode(dentry)))
- *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR);
- else
- *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_TIME_METADATA);
- }
-
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
status = nfsd4_encode_security_label(xdr, rqstp, context,
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index cb742e17e04a..40cb40ac0a65 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -387,7 +387,6 @@ void nfsd_lockd_shutdown(void);
#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
(NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
- FATTR4_WORD2_CHANGE_ATTR_TYPE | \
FATTR4_WORD2_MODE_UMASK | \
NFSD4_2_SECURITY_ATTRS | \
FATTR4_WORD2_XATTR_SUPPORT)
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 9dc7eeac924f..5b4c67c91f56 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -385,13 +385,6 @@ enum lock_type4 {
NFS4_WRITEW_LT = 4
};
-enum change_attr_type4 {
- NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR = 0,
- NFS4_CHANGE_TYPE_IS_VERSION_COUNTER = 1,
- NFS4_CHANGE_TYPE_IS_VERSION_COUNTER_NOPNFS = 2,
- NFS4_CHANGE_TYPE_IS_TIME_METADATA = 3,
- NFS4_CHANGE_TYPE_IS_UNDEFINED = 4
-};
/* Mandatory Attributes */
#define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0)
@@ -459,7 +452,6 @@ enum change_attr_type4 {
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
#define FATTR4_WORD2_CLONE_BLKSIZE (1UL << 13)
-#define FATTR4_WORD2_CHANGE_ATTR_TYPE (1UL << 15)
#define FATTR4_WORD2_SECURITY_LABEL (1UL << 16)
#define FATTR4_WORD2_MODE_UMASK (1UL << 17)
#define FATTR4_WORD2_XATTR_SUPPORT (1UL << 18)
--
2.28.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
` (3 preceding siblings ...)
2020-11-30 22:46 ` [PATCH 5/5] Revert "nfsd4: support change_attr_type attribute" J. Bruce Fields
@ 2020-12-01 16:30 ` Jeff Layton
2020-12-01 20:12 ` J. Bruce Fields
2020-12-01 16:43 ` Jeff Layton
5 siblings, 1 reply; 14+ messages in thread
From: Jeff Layton @ 2020-12-01 16:30 UTC (permalink / raw)
To: J. Bruce Fields, Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
On Mon, 2020-11-30 at 17:46 -0500, J. Bruce Fields wrote:
> From: "J. Bruce Fields" <bfields@redhat.com>
>
> inode_query_iversion() can modify i_version. Depending on the exported
> filesystem, that may not be safe. For example, if you're re-exporting
> NFS, NFS stores the server's change attribute in i_version and does not
> expect it to be modified locally. This has been observed causing
> unnecessary cache invalidations.
>
> The way a filesystem indicates that it's OK to call
> inode_query_iverson() is by setting SB_I_VERSION.
>
> So, move the I_VERSION check out of encode_change(), where it's used
> only in FATTR responses, to nfsd4_changeattr(), which is also called for
> pre- and post- operation attributes.
>
"only in FATTR responses, to nfsd4_change_attribute(),"
> (Note we could also pull the NFSEXP_V4ROOT case into
> nfsd4_change_attribute as well. That would actually be a no-op, since
> pre/post attrs are only used for metadata-modifying operations, and
> V4ROOT exports are read-only. But we might make the change in the
> future just for simplicity.)
>
> Reported-by: Daire Byrne <daire@dneg.com>
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/nfsd/nfs3xdr.c | 5 ++---
> fs/nfsd/nfs4xdr.c | 6 +-----
> fs/nfsd/nfsfh.h | 14 ++++++++++----
> 3 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index 2277f83da250..dfbf390ff40c 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> printk("nfsd: inode locked twice during operation.\n");
>
>
>
>
> err = fh_getattr(fhp, &fhp->fh_post_attr);
> - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> - d_inode(fhp->fh_dentry));
> if (err) {
> fhp->fh_post_saved = false;
> - /* Grab the ctime anyway - set_change_info might use it */
> fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> } else
> fhp->fh_post_saved = true;
> + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> + d_inode(fhp->fh_dentry));
> }
>
>
>
>
> /*
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 833a2c64dfe8..56fd5f6d5c44 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> if (exp->ex_flags & NFSEXP_V4ROOT) {
> *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> *p++ = 0;
> - } else if (IS_I_VERSION(inode)) {
> + } else
> p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> - } else {
> - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> - }
> return p;
> }
>
>
>
>
> diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> index 56cfbc361561..39d764b129fa 100644
> --- a/fs/nfsd/nfsfh.h
> +++ b/fs/nfsd/nfsfh.h
> @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> {
> u64 chattr;
>
>
>
>
> - chattr = stat->ctime.tv_sec;
> - chattr <<= 30;
> - chattr += stat->ctime.tv_nsec;
> - chattr += inode_query_iversion(inode);
> + if (IS_I_VERSION(inode)) {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 30;
> + chattr += stat->ctime.tv_nsec;
> + chattr += inode_query_iversion(inode);
> + } else {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 32;
> + chattr += stat->ctime.tv_nsec;
> + }
> return chattr;
> }
>
>
>
>
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
` (4 preceding siblings ...)
2020-12-01 16:30 ` [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case Jeff Layton
@ 2020-12-01 16:43 ` Jeff Layton
2020-12-01 20:38 ` J. Bruce Fields
2020-12-01 21:35 ` J. Bruce Fields
5 siblings, 2 replies; 14+ messages in thread
From: Jeff Layton @ 2020-12-01 16:43 UTC (permalink / raw)
To: J. Bruce Fields, Chuck Lever; +Cc: linux-nfs, J. Bruce Fields
On Mon, 2020-11-30 at 17:46 -0500, J. Bruce Fields wrote:
> From: "J. Bruce Fields" <bfields@redhat.com>
>
> inode_query_iversion() can modify i_version. Depending on the exported
> filesystem, that may not be safe. For example, if you're re-exporting
> NFS, NFS stores the server's change attribute in i_version and does not
> expect it to be modified locally. This has been observed causing
> unnecessary cache invalidations.
>
> The way a filesystem indicates that it's OK to call
> inode_query_iverson() is by setting SB_I_VERSION.
>
> So, move the I_VERSION check out of encode_change(), where it's used
> only in FATTR responses, to nfsd4_changeattr(), which is also called for
> pre- and post- operation attributes.
>
> (Note we could also pull the NFSEXP_V4ROOT case into
> nfsd4_change_attribute as well. That would actually be a no-op, since
> pre/post attrs are only used for metadata-modifying operations, and
> V4ROOT exports are read-only. But we might make the change in the
> future just for simplicity.)
>
> Reported-by: Daire Byrne <daire@dneg.com>
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/nfsd/nfs3xdr.c | 5 ++---
> fs/nfsd/nfs4xdr.c | 6 +-----
> fs/nfsd/nfsfh.h | 14 ++++++++++----
> 3 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index 2277f83da250..dfbf390ff40c 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> printk("nfsd: inode locked twice during operation.\n");
>
>
>
>
> err = fh_getattr(fhp, &fhp->fh_post_attr);
> - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> - d_inode(fhp->fh_dentry));
> if (err) {
> fhp->fh_post_saved = false;
> - /* Grab the ctime anyway - set_change_info might use it */
> fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> } else
> fhp->fh_post_saved = true;
> + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> + d_inode(fhp->fh_dentry));
> }
>
>
>
>
> /*
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 833a2c64dfe8..56fd5f6d5c44 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> if (exp->ex_flags & NFSEXP_V4ROOT) {
> *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> *p++ = 0;
> - } else if (IS_I_VERSION(inode)) {
> + } else
> p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> - } else {
> - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> - }
> return p;
> }
>
>
>
>
> diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> index 56cfbc361561..39d764b129fa 100644
> --- a/fs/nfsd/nfsfh.h
> +++ b/fs/nfsd/nfsfh.h
> @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> {
> u64 chattr;
>
>
>
>
> - chattr = stat->ctime.tv_sec;
> - chattr <<= 30;
> - chattr += stat->ctime.tv_nsec;
> - chattr += inode_query_iversion(inode);
> + if (IS_I_VERSION(inode)) {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 30;
> + chattr += stat->ctime.tv_nsec;
> + chattr += inode_query_iversion(inode);
> + } else {
> + chattr = stat->ctime.tv_sec;
> + chattr <<= 32;
Might be nice to annotate the shifts above and maybe make them named
constants. I'm not sure where those values come from, tbh.
> + chattr += stat->ctime.tv_nsec;
> + }
> return chattr;
> }
>
>
>
>
Other than some very minor nits, the set itself looks great.
Are you planning to follow up with the series to add the fetch_iversion
op, or have you decided not to do that for now?
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-12-01 16:30 ` [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case Jeff Layton
@ 2020-12-01 20:12 ` J. Bruce Fields
0 siblings, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-12-01 20:12 UTC (permalink / raw)
To: Jeff Layton; +Cc: J. Bruce Fields, Chuck Lever, linux-nfs
On Tue, Dec 01, 2020 at 11:30:12AM -0500, Jeff Layton wrote:
> On Mon, 2020-11-30 at 17:46 -0500, J. Bruce Fields wrote:
> > From: "J. Bruce Fields" <bfields@redhat.com>
> >
> > inode_query_iversion() can modify i_version. Depending on the exported
> > filesystem, that may not be safe. For example, if you're re-exporting
> > NFS, NFS stores the server's change attribute in i_version and does not
> > expect it to be modified locally. This has been observed causing
> > unnecessary cache invalidations.
> >
> > The way a filesystem indicates that it's OK to call
> > inode_query_iverson() is by setting SB_I_VERSION.
> >
> > So, move the I_VERSION check out of encode_change(), where it's used
> > only in FATTR responses, to nfsd4_changeattr(), which is also called for
> > pre- and post- operation attributes.
> >
>
> "only in FATTR responses, to nfsd4_change_attribute(),"
Whoops, and also FATTR should have been GETATTR.
Fixed locally, I assume Chuck will just want to fix that up in his tree
(let me know if not).
--b.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-12-01 16:43 ` Jeff Layton
@ 2020-12-01 20:38 ` J. Bruce Fields
2020-12-01 21:35 ` J. Bruce Fields
1 sibling, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-12-01 20:38 UTC (permalink / raw)
To: Jeff Layton; +Cc: J. Bruce Fields, Chuck Lever, linux-nfs
On Tue, Dec 01, 2020 at 11:43:31AM -0500, Jeff Layton wrote:
> On Mon, 2020-11-30 at 17:46 -0500, J. Bruce Fields wrote:
> > From: "J. Bruce Fields" <bfields@redhat.com>
> >
> > inode_query_iversion() can modify i_version. Depending on the exported
> > filesystem, that may not be safe. For example, if you're re-exporting
> > NFS, NFS stores the server's change attribute in i_version and does not
> > expect it to be modified locally. This has been observed causing
> > unnecessary cache invalidations.
> >
> > The way a filesystem indicates that it's OK to call
> > inode_query_iverson() is by setting SB_I_VERSION.
> >
> > So, move the I_VERSION check out of encode_change(), where it's used
> > only in FATTR responses, to nfsd4_changeattr(), which is also called for
> > pre- and post- operation attributes.
> >
> > (Note we could also pull the NFSEXP_V4ROOT case into
> > nfsd4_change_attribute as well. That would actually be a no-op, since
> > pre/post attrs are only used for metadata-modifying operations, and
> > V4ROOT exports are read-only. But we might make the change in the
> > future just for simplicity.)
> >
> > Reported-by: Daire Byrne <daire@dneg.com>
> > Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> > ---
> > fs/nfsd/nfs3xdr.c | 5 ++---
> > fs/nfsd/nfs4xdr.c | 6 +-----
> > fs/nfsd/nfsfh.h | 14 ++++++++++----
> > 3 files changed, 13 insertions(+), 12 deletions(-)
> >
> > diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> > index 2277f83da250..dfbf390ff40c 100644
> > --- a/fs/nfsd/nfs3xdr.c
> > +++ b/fs/nfsd/nfs3xdr.c
> > @@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp)
> > printk("nfsd: inode locked twice during operation.\n");
> >
> >
> >
> >
> > err = fh_getattr(fhp, &fhp->fh_post_attr);
> > - fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> > - d_inode(fhp->fh_dentry));
> > if (err) {
> > fhp->fh_post_saved = false;
> > - /* Grab the ctime anyway - set_change_info might use it */
> > fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
> > } else
> > fhp->fh_post_saved = true;
> > + fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
> > + d_inode(fhp->fh_dentry));
> > }
> >
> >
> >
> >
> > /*
> > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > index 833a2c64dfe8..56fd5f6d5c44 100644
> > --- a/fs/nfsd/nfs4xdr.c
> > +++ b/fs/nfsd/nfs4xdr.c
> > @@ -2298,12 +2298,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
> > if (exp->ex_flags & NFSEXP_V4ROOT) {
> > *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
> > *p++ = 0;
> > - } else if (IS_I_VERSION(inode)) {
> > + } else
> > p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
> > - } else {
> > - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> > - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
> > - }
> > return p;
> > }
> >
> >
> >
> >
> > diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
> > index 56cfbc361561..39d764b129fa 100644
> > --- a/fs/nfsd/nfsfh.h
> > +++ b/fs/nfsd/nfsfh.h
> > @@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
> > {
> > u64 chattr;
> >
> >
> >
> >
> > - chattr = stat->ctime.tv_sec;
> > - chattr <<= 30;
> > - chattr += stat->ctime.tv_nsec;
> > - chattr += inode_query_iversion(inode);
> > + if (IS_I_VERSION(inode)) {
> > + chattr = stat->ctime.tv_sec;
> > + chattr <<= 30;
> > + chattr += stat->ctime.tv_nsec;
> > + chattr += inode_query_iversion(inode);
> > + } else {
> > + chattr = stat->ctime.tv_sec;
> > + chattr <<= 32;
>
> Might be nice to annotate the shifts above and maybe make them named
> constants. I'm not sure where those values come from, tbh.
This shouldn't be changing the on-the-wire results at all; so
for example the latter is just doing exactly what:
> > - *p++ = cpu_to_be32(stat->ctime.tv_sec);
> > - *p++ = cpu_to_be32(stat->ctime.tv_nsec);
did (after xdr-encoding of the 64-bit chattr).
But yeah maybe it could use some explanation.
The 30-bit shift in the IS_I_VERSION case is weirder, I honestly don't
remember what I was thinking. Maybe just that nanoseconds really only
need 30 bits, and the shift would save a couple high bits in case we
wanted to change the format later without making the change attribute go
backwards. Probably overthinking it!
--b.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case
2020-12-01 16:43 ` Jeff Layton
2020-12-01 20:38 ` J. Bruce Fields
@ 2020-12-01 21:35 ` J. Bruce Fields
1 sibling, 0 replies; 14+ messages in thread
From: J. Bruce Fields @ 2020-12-01 21:35 UTC (permalink / raw)
To: Jeff Layton; +Cc: Chuck Lever, linux-nfs, J. Bruce Fields
On Tue, Dec 01, 2020 at 11:43:31AM -0500, Jeff Layton wrote:
> Are you planning to follow up with the series to add the fetch_iversion
> op, or have you decided not to do that for now?
I'm still interested. I just figured it's not urgent, and it'll be
easier to ask for fs-devel review after this other stuff is in, so it
may as well wait till after the merge window.
--b.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2020-12-01 21:36 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-30 22:46 [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case J. Bruce Fields
2020-11-30 22:46 ` [PATCH 2/5] nfsd: simplify nfsd4_change_info J. Bruce Fields
2020-11-30 22:46 ` [PATCH 3/5] nfsd: minor nfsd4_change_attribute cleanup J. Bruce Fields
2020-11-30 22:46 ` [PATCH 4/5] nfsd4: don't query change attribute in v2/v3 case J. Bruce Fields
2020-11-30 22:46 ` [PATCH 5/5] Revert "nfsd4: support change_attr_type attribute" J. Bruce Fields
2020-12-01 16:30 ` [PATCH 1/5] nfsd: only call inode_query_iversion in the I_VERSION case Jeff Layton
2020-12-01 20:12 ` J. Bruce Fields
2020-12-01 16:43 ` Jeff Layton
2020-12-01 20:38 ` J. Bruce Fields
2020-12-01 21:35 ` J. Bruce Fields
-- strict thread matches above, loose matches on Subject: below --
2020-11-30 19:38 J. Bruce Fields
2020-11-30 19:46 ` J. Bruce Fields
2020-11-30 21:03 ` Chuck Lever
2020-11-30 21:42 ` Bruce Fields
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).