Skip to content

Commit 28331a4

Browse files
Trond MyklebustTrond Myklebust
authored andcommitted
NFSv4: Ensure we request the ordinary fileid when doing readdirplus
When readdir() returns a directory entry for the root of a mounted filesystem, Linux follows the old convention of returning the inode number of the covered directory (despite newer versions of POSIX declaring that this is a bug). To ensure this continues to work, the NFSv4 readdir implementation requests the 'mounted-on-fileid' from the server. However, readdirplus also needs to instantiate an inode for this entry, and for that, we also need to request the real fileid as per this patch. Signed-off-by: Trond Myklebust <[email protected]>
1 parent 1bd714f commit 28331a4

File tree

2 files changed

+16
-17
lines changed

2 files changed

+16
-17
lines changed

fs/nfs/nfs4xdr.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
14521452

14531453
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
14541454
{
1455-
uint32_t attrs[2] = {0, 0};
1455+
uint32_t attrs[2] = {
1456+
FATTR4_WORD0_RDATTR_ERROR,
1457+
FATTR4_WORD1_MOUNTED_ON_FILEID,
1458+
};
14561459
uint32_t dircount = readdir->count >> 1;
14571460
__be32 *p;
14581461

14591462
if (readdir->plus) {
14601463
attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
1461-
FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
1464+
FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
14621465
attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
14631466
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
14641467
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
14651468
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
14661469
dircount >>= 1;
14671470
}
1468-
attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
1469-
attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
1470-
/* Switch to mounted_on_fileid if the server supports it */
1471-
if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
1472-
attrs[0] &= ~FATTR4_WORD0_FILEID;
1473-
else
1474-
attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
1471+
/* Use mounted_on_fileid only if the server supports it */
1472+
if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
1473+
attrs[0] |= FATTR4_WORD0_FILEID;
14751474

14761475
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
14771476
*p++ = cpu_to_be32(OP_READDIR);
@@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
31403139
goto out_overflow;
31413140
xdr_decode_hyper(p, fileid);
31423141
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
3143-
ret = NFS_ATTR_FATTR_FILEID;
3142+
ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
31443143
}
31453144
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
31463145
return ret;
@@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
40024001
{
40034002
int status;
40044003
umode_t fmode = 0;
4005-
uint64_t fileid;
40064004
uint32_t type;
40074005

40084006
status = decode_attr_type(xdr, bitmap, &type);
@@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
41014099
goto xdr_error;
41024100
fattr->valid |= status;
41034101

4104-
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
4102+
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
41054103
if (status < 0)
41064104
goto xdr_error;
4107-
if (status != 0 && !(fattr->valid & status)) {
4108-
fattr->fileid = fileid;
4109-
fattr->valid |= status;
4110-
}
4105+
fattr->valid |= status;
41114106

41124107
xdr_error:
41134108
dprintk("%s: xdr returned %d\n", __func__, -status);
@@ -6411,7 +6406,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
64116406
if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
64126407
entry->server, 1) < 0)
64136408
goto out_overflow;
6414-
if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
6409+
if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
6410+
entry->ino = entry->fattr->mounted_on_fileid;
6411+
else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
64156412
entry->ino = entry->fattr->fileid;
64166413

64176414
entry->d_type = DT_UNKNOWN;

include/linux/nfs_xdr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct nfs_fattr {
5050
} du;
5151
struct nfs_fsid fsid;
5252
__u64 fileid;
53+
__u64 mounted_on_fileid;
5354
struct timespec atime;
5455
struct timespec mtime;
5556
struct timespec ctime;
@@ -83,6 +84,7 @@ struct nfs_fattr {
8384
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
8485
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
8586
#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */
87+
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21)
8688

8789
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
8890
| NFS_ATTR_FATTR_MODE \

0 commit comments

Comments
 (0)