On Mon, 21 Jun 2021, Wang Yugui wrote: > Hi, > > > > > It seems more fixes are needed. > > > > > > I think the problem is that the submount doesn't appear in /proc/mounts. > > > "nfsd_fh()" in nfs-utils needs to be able to map from the uuid for a > > > filesystem to the mount point. To do this it walks through /proc/mounts > > > checking the uuid of each filesystem. If a filesystem isn't listed > > > there, it obviously fails. > > > > > > I guess you could add code to nfs-utils to do whatever "btrfs subvol > > > list" does to make up for the fact that btrfs doesn't register in > > > /proc/mounts. > > > > Another approach might be to just change svcxdr_encode_fattr3() and > > nfsd4_encode_fattr() in the 'FSIDSOJURCE_UUID' case to check if > > dentry->d_inode has a different btrfs volume id to > > exp->ex_path.dentry->d_inode. > > If it does, then mix the volume id into the fsid somehow. > > > > With that, you wouldn't want the first change I suggested. > > This is what I have done. and it is based on linux 5.10.44 > > but it still not work, so still more jobs needed. > The following is more what I had in mind. It doesn't quite work and I cannot work out why. If you 'stat' a file inside the subvol, then 'find' will not complete. If you don't, then it will. Doing that 'stat' changes the st_dev number of the main filesystem, which seems really weird. I'm probably missing something obvious. Maybe a more careful analysis of what is changing when will help. NeilBrown diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 9421dae22737..790a3357525d 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/namei.h> #include <linux/module.h> +#include <linux/statfs.h> #include <linux/exportfs.h> #include <linux/sunrpc/svc_xprt.h> @@ -575,6 +576,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) int err; struct auth_domain *dom = NULL; struct svc_export exp = {}, *expp; + struct kstatfs statfs; int an_int; if (mesg[mlen-1] != '\n') @@ -604,6 +606,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) err = kern_path(buf, 0, &exp.ex_path); if (err) goto out1; + err = vfs_statfs(&exp.ex_path, &statfs); + if (err) + goto out3; + exp.ex_fsid64 = statfs.f_fsid; exp.ex_client = dom; exp.cd = cd; @@ -809,6 +815,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_anon_uid = item->ex_anon_uid; new->ex_anon_gid = item->ex_anon_gid; new->ex_fsid = item->ex_fsid; + new->ex_fsid64 = item->ex_fsid64; new->ex_devid_map = item->ex_devid_map; item->ex_devid_map = NULL; new->ex_uuid = item->ex_uuid; diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index ee0e3aba4a6e..d3eb9a599918 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -68,6 +68,7 @@ struct svc_export { kuid_t ex_anon_uid; kgid_t ex_anon_gid; int ex_fsid; + __kernel_fsid_t ex_fsid64; unsigned char * ex_uuid; /* 16 byte fsid */ struct nfsd4_fs_locations ex_fslocs; uint32_t ex_nflavors; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7abeccb975b2..8144e6037eae 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2869,6 +2869,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, if (err) goto out_nfserr; if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | + FATTR4_WORD0_FSID | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { @@ -3024,6 +3025,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, case FSIDSOURCE_UUID: p = xdr_encode_opaque_fixed(p, exp->ex_uuid, EX_UUID_LEN); + if (statfs.f_fsid.val[0] != exp->ex_fsid64.val[0] || + statfs.f_fsid.val[1] != exp->ex_fsid64.val[1]) { + /* looks like a btrfs subvol */ + p[-2] ^= statfs.f_fsid.val[0]; + p[-1] ^= statfs.f_fsid.val[1]; + } break; } }