aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2011-04-27 13:47:52 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-04-27 15:57:16 -0400
commit28331a46d88459788c8fca72dbb0415cd7f514c9 (patch)
tree436a4a7209ab9acab87c0e0ecb0cac9b2c749f3d /fs/nfs
parent1bd714f2a14aa4d6a5570956fcec64530b007e4a (diff)
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4xdr.c31
1 files changed, 14 insertions, 17 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index ba952bdc4d62..7310d2ec5de8 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
1452 1452
1453static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) 1453static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
1454{ 1454{
1455 uint32_t attrs[2] = {0, 0}; 1455 uint32_t attrs[2] = {
1456 FATTR4_WORD0_RDATTR_ERROR,
1457 FATTR4_WORD1_MOUNTED_ON_FILEID,
1458 };
1456 uint32_t dircount = readdir->count >> 1; 1459 uint32_t dircount = readdir->count >> 1;
1457 __be32 *p; 1460 __be32 *p;
1458 1461
1459 if (readdir->plus) { 1462 if (readdir->plus) {
1460 attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| 1463 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;
1462 attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| 1465 attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
1463 FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| 1466 FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
1464 FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| 1467 FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
1465 FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; 1468 FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
1466 dircount >>= 1; 1469 dircount >>= 1;
1467 } 1470 }
1468 attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; 1471 /* Use mounted_on_fileid only if the server supports it */
1469 attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; 1472 if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
1470 /* Switch to mounted_on_fileid if the server supports it */ 1473 attrs[0] |= FATTR4_WORD0_FILEID;
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;
1475 1474
1476 p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); 1475 p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
1477 *p++ = cpu_to_be32(OP_READDIR); 1476 *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 goto out_overflow; 3139 goto out_overflow;
3141 xdr_decode_hyper(p, fileid); 3140 xdr_decode_hyper(p, fileid);
3142 bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; 3141 bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
3143 ret = NFS_ATTR_FATTR_FILEID; 3142 ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
3144 } 3143 }
3145 dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); 3144 dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
3146 return ret; 3145 return ret;
@@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
4002{ 4001{
4003 int status; 4002 int status;
4004 umode_t fmode = 0; 4003 umode_t fmode = 0;
4005 uint64_t fileid;
4006 uint32_t type; 4004 uint32_t type;
4007 4005
4008 status = decode_attr_type(xdr, bitmap, &type); 4006 status = decode_attr_type(xdr, bitmap, &type);
@@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
4101 goto xdr_error; 4099 goto xdr_error;
4102 fattr->valid |= status; 4100 fattr->valid |= status;
4103 4101
4104 status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid); 4102 status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
4105 if (status < 0) 4103 if (status < 0)
4106 goto xdr_error; 4104 goto xdr_error;
4107 if (status != 0 && !(fattr->valid & status)) { 4105 fattr->valid |= status;
4108 fattr->fileid = fileid;
4109 fattr->valid |= status;
4110 }
4111 4106
4112xdr_error: 4107xdr_error:
4113 dprintk("%s: xdr returned %d\n", __func__, -status); 4108 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 if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, 6406 if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
6412 entry->server, 1) < 0) 6407 entry->server, 1) < 0)
6413 goto out_overflow; 6408 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)
6415 entry->ino = entry->fattr->fileid; 6412 entry->ino = entry->fattr->fileid;
6416 6413
6417 entry->d_type = DT_UNKNOWN; 6414 entry->d_type = DT_UNKNOWN;