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)
|
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;
|
uint32_t dircount = readdir->count >> 1;
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
|
|
||||||
if (readdir->plus) {
|
if (readdir->plus) {
|
||||||
attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
|
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|
|
attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
|
||||||
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
|
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
|
||||||
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
|
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
|
||||||
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
|
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
|
||||||
dircount >>= 1;
|
dircount >>= 1;
|
||||||
}
|
}
|
||||||
attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
|
/* Use mounted_on_fileid only if the server supports it */
|
||||||
attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
|
if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
|
||||||
/* Switch to mounted_on_fileid if the server supports it */
|
attrs[0] |= FATTR4_WORD0_FILEID;
|
||||||
if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
|
|
||||||
attrs[0] &= ~FATTR4_WORD0_FILEID;
|
|
||||||
else
|
|
||||||
attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
|
|
||||||
|
|
||||||
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
|
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
|
||||||
*p++ = cpu_to_be32(OP_READDIR);
|
*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;
|
goto out_overflow;
|
||||||
xdr_decode_hyper(p, fileid);
|
xdr_decode_hyper(p, fileid);
|
||||||
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_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);
|
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
umode_t fmode = 0;
|
umode_t fmode = 0;
|
||||||
uint64_t fileid;
|
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
|
|
||||||
status = decode_attr_type(xdr, bitmap, &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;
|
goto xdr_error;
|
||||||
fattr->valid |= status;
|
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)
|
if (status < 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
if (status != 0 && !(fattr->valid & status)) {
|
fattr->valid |= status;
|
||||||
fattr->fileid = fileid;
|
|
||||||
fattr->valid |= status;
|
|
||||||
}
|
|
||||||
|
|
||||||
xdr_error:
|
xdr_error:
|
||||||
dprintk("%s: xdr returned %d\n", __func__, -status);
|
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,
|
if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
|
||||||
entry->server, 1) < 0)
|
entry->server, 1) < 0)
|
||||||
goto out_overflow;
|
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->ino = entry->fattr->fileid;
|
||||||
|
|
||||||
entry->d_type = DT_UNKNOWN;
|
entry->d_type = DT_UNKNOWN;
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct nfs_fattr {
|
||||||
} du;
|
} du;
|
||||||
struct nfs_fsid fsid;
|
struct nfs_fsid fsid;
|
||||||
__u64 fileid;
|
__u64 fileid;
|
||||||
|
__u64 mounted_on_fileid;
|
||||||
struct timespec atime;
|
struct timespec atime;
|
||||||
struct timespec mtime;
|
struct timespec mtime;
|
||||||
struct timespec ctime;
|
struct timespec ctime;
|
||||||
|
@ -83,6 +84,7 @@ struct nfs_fattr {
|
||||||
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
|
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
|
||||||
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
|
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
|
||||||
#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */
|
#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 \
|
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
||||||
| NFS_ATTR_FATTR_MODE \
|
| NFS_ATTR_FATTR_MODE \
|
||||||
|
|
Loading…
Reference in New Issue