On Wed, 10 Sep 2025, Chuck Lever wrote: > +static __be32 > +nfsd_file_getattr(const struct svc_fh *fhp, struct nfsd_file *nf) <bikeshed> should this function have a name which reflects the fact that it is getting the dio attrs, not all attrs? e.h. nfsd_file_get_dio_attr() .... > @@ -1166,6 +1198,8 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net, > } > status = nfserrno(ret); > trace_nfsd_file_open(nf, status); > + if (status == nfs_ok) > + status = nfsd_file_getattr(fhp, nf); > } I ask because this stanza looks strange. "Why are the file attrs being got here?" I ask. Oh, it is really getting the dio attrs - that makes sense. </bikeshed> Thanks, NeilBrown > } else > status = nfserr_jukebox; > diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h > index 24ddf60e8434..e3d6ca2b6030 100644 > --- a/fs/nfsd/filecache.h > +++ b/fs/nfsd/filecache.h > @@ -54,6 +54,10 @@ struct nfsd_file { > struct list_head nf_gc; > struct rcu_head nf_rcu; > ktime_t nf_birthtime; > + > + u32 nf_dio_mem_align; > + u32 nf_dio_offset_align; > + u32 nf_dio_read_offset_align; > }; > > int nfsd_file_cache_init(void); > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c > index 3edccc38db42..3eb724ec9566 100644 > --- a/fs/nfsd/nfsfh.c > +++ b/fs/nfsd/nfsfh.c > @@ -696,8 +696,12 @@ __be32 fh_getattr(const struct svc_fh *fhp, struct kstat *stat) > .mnt = fhp->fh_export->ex_path.mnt, > .dentry = fhp->fh_dentry, > }; > + struct inode *inode = d_inode(p.dentry); > u32 request_mask = STATX_BASIC_STATS; > > + if (S_ISREG(inode->i_mode)) > + request_mask |= (STATX_DIOALIGN | STATX_DIO_READ_ALIGN); > + > if (fhp->fh_maxsize == NFS4_FHSIZE) > request_mask |= (STATX_BTIME | STATX_CHANGE_COOKIE); > > diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h > index a664fdf1161e..e5af0d058fd0 100644 > --- a/fs/nfsd/trace.h > +++ b/fs/nfsd/trace.h > @@ -1133,6 +1133,33 @@ TRACE_EVENT(nfsd_file_alloc, > ) > ); > > +TRACE_EVENT(nfsd_file_getattr, > + TP_PROTO( > + const struct inode *inode, > + const struct kstat *stat > + ), > + TP_ARGS(inode, stat), > + TP_STRUCT__entry( > + __field(const void *, inode) > + __field(unsigned long, mask) > + __field(u32, mem_align) > + __field(u32, offset_align) > + __field(u32, read_offset_align) > + ), > + TP_fast_assign( > + __entry->inode = inode; > + __entry->mask = stat->result_mask; > + __entry->mem_align = stat->dio_mem_align; > + __entry->offset_align = stat->dio_offset_align; > + __entry->read_offset_align = stat->dio_read_offset_align; > + ), > + TP_printk("inode=%p flags=%s mem_align=%u offset_align=%u read_offset_align=%u", > + __entry->inode, show_statx_mask(__entry->mask), > + __entry->mem_align, __entry->offset_align, > + __entry->read_offset_align > + ) > +); > + > TRACE_EVENT(nfsd_file_acquire, > TP_PROTO( > const struct svc_rqst *rqstp, > diff --git a/include/trace/misc/fs.h b/include/trace/misc/fs.h > index 0406ebe2a80a..7ead1c61f0cb 100644 > --- a/include/trace/misc/fs.h > +++ b/include/trace/misc/fs.h > @@ -141,3 +141,25 @@ > { ATTR_TIMES_SET, "TIMES_SET" }, \ > { ATTR_TOUCH, "TOUCH"}, \ > { ATTR_DELEG, "DELEG"}) > + > +#define show_statx_mask(flags) \ > + __print_flags(flags, "|", \ > + { STATX_TYPE, "TYPE" }, \ > + { STATX_MODE, "MODE" }, \ > + { STATX_NLINK, "NLINK" }, \ > + { STATX_UID, "UID" }, \ > + { STATX_GID, "GID" }, \ > + { STATX_ATIME, "ATIME" }, \ > + { STATX_MTIME, "MTIME" }, \ > + { STATX_CTIME, "CTIME" }, \ > + { STATX_INO, "INO" }, \ > + { STATX_SIZE, "SIZE" }, \ > + { STATX_BLOCKS, "BLOCKS" }, \ > + { STATX_BASIC_STATS, "BASIC_STATS" }, \ > + { STATX_BTIME, "BTIME" }, \ > + { STATX_MNT_ID, "MNT_ID" }, \ > + { STATX_DIOALIGN, "DIOALIGN" }, \ > + { STATX_MNT_ID_UNIQUE, "MNT_ID_UNIQUE" }, \ > + { STATX_SUBVOL, "SUBVOL" }, \ > + { STATX_WRITE_ATOMIC, "WRITE_ATOMIC" }, \ > + { STATX_DIO_READ_ALIGN, "DIO_READ_ALIGN" }) > -- > 2.50.0 > >