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 <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
1bd714f2a1
commit
28331a46d8
@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
|
||||
|
||||
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
|
||||
{
|
||||
uint32_t attrs[2] = {0, 0};
|
||||
uint32_t attrs[2] = {
|
||||
FATTR4_WORD0_RDATTR_ERROR,
|
||||
FATTR4_WORD1_MOUNTED_ON_FILEID,
|
||||
};
|
||||
uint32_t dircount = readdir->count >> 1;
|
||||
__be32 *p;
|
||||
|
||||
if (readdir->plus) {
|
||||
attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
|
||||
FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
|
||||
FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
|
||||
attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
|
||||
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
|
||||
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
|
||||
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
|
||||
dircount >>= 1;
|
||||
}
|
||||
attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
|
||||
attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
|
||||
/* Switch to mounted_on_fileid if the server supports it */
|
||||
if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
|
||||
attrs[0] &= ~FATTR4_WORD0_FILEID;
|
||||
else
|
||||
attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
|
||||
/* Use mounted_on_fileid only if the server supports it */
|
||||
if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
|
||||
attrs[0] |= FATTR4_WORD0_FILEID;
|
||||
|
||||
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
|
||||
*p++ = cpu_to_be32(OP_READDIR);
|
||||
@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
|
||||
goto out_overflow;
|
||||
xdr_decode_hyper(p, fileid);
|
||||
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
|
||||
ret = NFS_ATTR_FATTR_FILEID;
|
||||
ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
|
||||
}
|
||||
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
|
||||
return ret;
|
||||
@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
{
|
||||
int status;
|
||||
umode_t fmode = 0;
|
||||
uint64_t fileid;
|
||||
uint32_t type;
|
||||
|
||||
status = decode_attr_type(xdr, bitmap, &type);
|
||||
@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
goto xdr_error;
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
|
||||
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if (status != 0 && !(fattr->valid & status)) {
|
||||
fattr->fileid = fileid;
|
||||
fattr->valid |= status;
|
||||
}
|
||||
fattr->valid |= status;
|
||||
|
||||
xdr_error:
|
||||
dprintk("%s: xdr returned %d\n", __func__, -status);
|
||||
@ -6411,7 +6406,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||
if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
|
||||
entry->server, 1) < 0)
|
||||
goto out_overflow;
|
||||
if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
|
||||
if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
|
||||
entry->ino = entry->fattr->mounted_on_fileid;
|
||||
else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
|
||||
entry->ino = entry->fattr->fileid;
|
||||
|
||||
entry->d_type = DT_UNKNOWN;
|
||||
|
@ -50,6 +50,7 @@ struct nfs_fattr {
|
||||
} du;
|
||||
struct nfs_fsid fsid;
|
||||
__u64 fileid;
|
||||
__u64 mounted_on_fileid;
|
||||
struct timespec atime;
|
||||
struct timespec mtime;
|
||||
struct timespec ctime;
|
||||
@ -83,6 +84,7 @@ struct nfs_fattr {
|
||||
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
|
||||
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
|
||||
#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */
|
||||
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21)
|
||||
|
||||
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
||||
| NFS_ATTR_FATTR_MODE \
|
||||
|
Loading…
Reference in New Issue
Block a user