diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-03-02 13:06:22 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-03-02 13:06:22 -0500 |
| commit | ebed9203b68a4f333ce5d17e874b26c3afcfeff1 (patch) | |
| tree | ec0c24396061eb662594a3b879acc760e41532b7 | |
| parent | 9fcfe0c83c3b04a759cde6b8c5f961237f17808b (diff) | |
NFS: Fix an allocation-under-spinlock bug
sunrpc_cache_update() will always call detail->update() from inside the
detail->hash_lock, so it cannot allocate memory.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org
| -rw-r--r-- | fs/nfs/dns_resolve.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 95e1ca765d47..3f0cd4dfddaf 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -36,6 +36,19 @@ struct nfs_dns_ent { | |||
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | 38 | ||
| 39 | static void nfs_dns_ent_update(struct cache_head *cnew, | ||
| 40 | struct cache_head *ckey) | ||
| 41 | { | ||
| 42 | struct nfs_dns_ent *new; | ||
| 43 | struct nfs_dns_ent *key; | ||
| 44 | |||
| 45 | new = container_of(cnew, struct nfs_dns_ent, h); | ||
| 46 | key = container_of(ckey, struct nfs_dns_ent, h); | ||
| 47 | |||
| 48 | memcpy(&new->addr, &key->addr, key->addrlen); | ||
| 49 | new->addrlen = key->addrlen; | ||
| 50 | } | ||
| 51 | |||
| 39 | static void nfs_dns_ent_init(struct cache_head *cnew, | 52 | static void nfs_dns_ent_init(struct cache_head *cnew, |
| 40 | struct cache_head *ckey) | 53 | struct cache_head *ckey) |
| 41 | { | 54 | { |
| @@ -49,8 +62,7 @@ static void nfs_dns_ent_init(struct cache_head *cnew, | |||
| 49 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); | 62 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); |
| 50 | if (new->hostname) { | 63 | if (new->hostname) { |
| 51 | new->namelen = key->namelen; | 64 | new->namelen = key->namelen; |
| 52 | memcpy(&new->addr, &key->addr, key->addrlen); | 65 | nfs_dns_ent_update(cnew, ckey); |
| 53 | new->addrlen = key->addrlen; | ||
| 54 | } else { | 66 | } else { |
| 55 | new->namelen = 0; | 67 | new->namelen = 0; |
| 56 | new->addrlen = 0; | 68 | new->addrlen = 0; |
| @@ -234,7 +246,7 @@ static struct cache_detail nfs_dns_resolve = { | |||
| 234 | .cache_show = nfs_dns_show, | 246 | .cache_show = nfs_dns_show, |
| 235 | .match = nfs_dns_match, | 247 | .match = nfs_dns_match, |
| 236 | .init = nfs_dns_ent_init, | 248 | .init = nfs_dns_ent_init, |
| 237 | .update = nfs_dns_ent_init, | 249 | .update = nfs_dns_ent_update, |
| 238 | .alloc = nfs_dns_ent_alloc, | 250 | .alloc = nfs_dns_ent_alloc, |
| 239 | }; | 251 | }; |
| 240 | 252 | ||
