diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-06-05 09:16:47 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-06-05 10:00:14 -0400 |
commit | 1549210fcc17e9ae20c09ac8cd4c48a8dfd431bd (patch) | |
tree | 87db73acf11d00c1c4366e488faf86cd70ed996a | |
parent | b3b02ae5865c2dcd506322e0fc6def59a042e72f (diff) |
NFSv4: Fix an Oops in the open recovery code
The open recovery code does not need to request a new value for the
mdsthreshold, and so does not allocate a struct nfs4_threshold.
The problem is that encode_getfattr_open() will still request an
mdsthreshold, and so we end up Oopsing in decode_attr_mdsthreshold.
This patch fixes encode_getfattr_open so that it doesn't request an
mdsthreshold when the caller isn't asking for one. It also fixes
decode_attr_mdsthreshold so that it errors if the server returns
an mdsthreshold that we didn't ask for (instead of Oopsing).
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Andy Adamson <andros@netapp.com>
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 22 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 12 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 1 |
4 files changed, 31 insertions, 6 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c6827f93ab57..cc5900ac61b5 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -295,7 +295,7 @@ is_ds_client(struct nfs_client *clp) | |||
295 | 295 | ||
296 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; | 296 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; |
297 | 297 | ||
298 | extern const u32 nfs4_fattr_bitmap[2]; | 298 | extern const u32 nfs4_fattr_bitmap[3]; |
299 | extern const u32 nfs4_statfs_bitmap[2]; | 299 | extern const u32 nfs4_statfs_bitmap[2]; |
300 | extern const u32 nfs4_pathconf_bitmap[2]; | 300 | extern const u32 nfs4_pathconf_bitmap[2]; |
301 | extern const u32 nfs4_fsinfo_bitmap[3]; | 301 | extern const u32 nfs4_fsinfo_bitmap[3]; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d48dbefa0e71..ad1515521a6a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -116,7 +116,7 @@ static int nfs4_map_errors(int err) | |||
116 | /* | 116 | /* |
117 | * This is our standard bitmap for GETATTR requests. | 117 | * This is our standard bitmap for GETATTR requests. |
118 | */ | 118 | */ |
119 | const u32 nfs4_fattr_bitmap[2] = { | 119 | const u32 nfs4_fattr_bitmap[3] = { |
120 | FATTR4_WORD0_TYPE | 120 | FATTR4_WORD0_TYPE |
121 | | FATTR4_WORD0_CHANGE | 121 | | FATTR4_WORD0_CHANGE |
122 | | FATTR4_WORD0_SIZE | 122 | | FATTR4_WORD0_SIZE |
@@ -133,6 +133,24 @@ const u32 nfs4_fattr_bitmap[2] = { | |||
133 | | FATTR4_WORD1_TIME_MODIFY | 133 | | FATTR4_WORD1_TIME_MODIFY |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static const u32 nfs4_pnfs_open_bitmap[3] = { | ||
137 | FATTR4_WORD0_TYPE | ||
138 | | FATTR4_WORD0_CHANGE | ||
139 | | FATTR4_WORD0_SIZE | ||
140 | | FATTR4_WORD0_FSID | ||
141 | | FATTR4_WORD0_FILEID, | ||
142 | FATTR4_WORD1_MODE | ||
143 | | FATTR4_WORD1_NUMLINKS | ||
144 | | FATTR4_WORD1_OWNER | ||
145 | | FATTR4_WORD1_OWNER_GROUP | ||
146 | | FATTR4_WORD1_RAWDEV | ||
147 | | FATTR4_WORD1_SPACE_USED | ||
148 | | FATTR4_WORD1_TIME_ACCESS | ||
149 | | FATTR4_WORD1_TIME_METADATA | ||
150 | | FATTR4_WORD1_TIME_MODIFY, | ||
151 | FATTR4_WORD2_MDSTHRESHOLD | ||
152 | }; | ||
153 | |||
136 | const u32 nfs4_statfs_bitmap[2] = { | 154 | const u32 nfs4_statfs_bitmap[2] = { |
137 | FATTR4_WORD0_FILES_AVAIL | 155 | FATTR4_WORD0_FILES_AVAIL |
138 | | FATTR4_WORD0_FILES_FREE | 156 | | FATTR4_WORD0_FILES_FREE |
@@ -844,6 +862,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
844 | p->o_arg.name = &dentry->d_name; | 862 | p->o_arg.name = &dentry->d_name; |
845 | p->o_arg.server = server; | 863 | p->o_arg.server = server; |
846 | p->o_arg.bitmask = server->attr_bitmask; | 864 | p->o_arg.bitmask = server->attr_bitmask; |
865 | p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; | ||
847 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 866 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
848 | if (attrs != NULL && attrs->ia_valid != 0) { | 867 | if (attrs != NULL && attrs->ia_valid != 0) { |
849 | __be32 verf[2]; | 868 | __be32 verf[2]; |
@@ -1820,6 +1839,7 @@ static int _nfs4_do_open(struct inode *dir, | |||
1820 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); | 1839 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); |
1821 | if (!opendata->f_attr.mdsthreshold) | 1840 | if (!opendata->f_attr.mdsthreshold) |
1822 | goto err_opendata_put; | 1841 | goto err_opendata_put; |
1842 | opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; | ||
1823 | } | 1843 | } |
1824 | if (dentry->d_inode != NULL) | 1844 | if (dentry->d_inode != NULL) |
1825 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); | 1845 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ee4a74db95d0..9ca1428da9d9 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1198,12 +1198,13 @@ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct c | |||
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, | 1200 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, |
1201 | const u32 *open_bitmap, | ||
1201 | struct compound_hdr *hdr) | 1202 | struct compound_hdr *hdr) |
1202 | { | 1203 | { |
1203 | encode_getattr_three(xdr, | 1204 | encode_getattr_three(xdr, |
1204 | bitmask[0] & nfs4_fattr_bitmap[0], | 1205 | bitmask[0] & open_bitmap[0], |
1205 | bitmask[1] & nfs4_fattr_bitmap[1], | 1206 | bitmask[1] & open_bitmap[1], |
1206 | bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD, | 1207 | bitmask[2] & open_bitmap[2], |
1207 | hdr); | 1208 | hdr); |
1208 | } | 1209 | } |
1209 | 1210 | ||
@@ -2221,7 +2222,7 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2221 | encode_putfh(xdr, args->fh, &hdr); | 2222 | encode_putfh(xdr, args->fh, &hdr); |
2222 | encode_open(xdr, args, &hdr); | 2223 | encode_open(xdr, args, &hdr); |
2223 | encode_getfh(xdr, &hdr); | 2224 | encode_getfh(xdr, &hdr); |
2224 | encode_getfattr_open(xdr, args->bitmask, &hdr); | 2225 | encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr); |
2225 | encode_nops(&hdr); | 2226 | encode_nops(&hdr); |
2226 | } | 2227 | } |
2227 | 2228 | ||
@@ -4360,6 +4361,9 @@ static int decode_attr_mdsthreshold(struct xdr_stream *xdr, | |||
4360 | if (unlikely(bitmap[2] & (FATTR4_WORD2_MDSTHRESHOLD - 1U))) | 4361 | if (unlikely(bitmap[2] & (FATTR4_WORD2_MDSTHRESHOLD - 1U))) |
4361 | return -EIO; | 4362 | return -EIO; |
4362 | if (likely(bitmap[2] & FATTR4_WORD2_MDSTHRESHOLD)) { | 4363 | if (likely(bitmap[2] & FATTR4_WORD2_MDSTHRESHOLD)) { |
4364 | /* Did the server return an unrequested attribute? */ | ||
4365 | if (unlikely(res == NULL)) | ||
4366 | return -EREMOTEIO; | ||
4363 | p = xdr_inline_decode(xdr, 4); | 4367 | p = xdr_inline_decode(xdr, 4); |
4364 | if (unlikely(!p)) | 4368 | if (unlikely(!p)) |
4365 | goto out_overflow; | 4369 | goto out_overflow; |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index d1a7bf51c326..7519baef025b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -348,6 +348,7 @@ struct nfs_openargs { | |||
348 | const struct qstr * name; | 348 | const struct qstr * name; |
349 | const struct nfs_server *server; /* Needed for ID mapping */ | 349 | const struct nfs_server *server; /* Needed for ID mapping */ |
350 | const u32 * bitmask; | 350 | const u32 * bitmask; |
351 | const u32 * open_bitmap; | ||
351 | __u32 claim; | 352 | __u32 claim; |
352 | struct nfs4_sequence_args seq_args; | 353 | struct nfs4_sequence_args seq_args; |
353 | }; | 354 | }; |