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 | }; |
