Commit 28331a46 authored by Trond Myklebust's avatar Trond Myklebust

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 1bd714f2
...@@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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 { ...@@ -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 \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment