NFS: Fix an allocation-under-spinlock bug
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 2 Mar 2010 18:06:22 +0000 (13:06 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 2 Mar 2010 18:06:22 +0000 (13:06 -0500)
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
fs/nfs/dns_resolve.c

index 95e1ca7..3f0cd4d 100644 (file)
@@ -36,6 +36,19 @@ struct nfs_dns_ent {
 };
 
 
+static void nfs_dns_ent_update(struct cache_head *cnew,
+               struct cache_head *ckey)
+{
+       struct nfs_dns_ent *new;
+       struct nfs_dns_ent *key;
+
+       new = container_of(cnew, struct nfs_dns_ent, h);
+       key = container_of(ckey, struct nfs_dns_ent, h);
+
+       memcpy(&new->addr, &key->addr, key->addrlen);
+       new->addrlen = key->addrlen;
+}
+
 static void nfs_dns_ent_init(struct cache_head *cnew,
                struct cache_head *ckey)
 {
@@ -49,8 +62,7 @@ static void nfs_dns_ent_init(struct cache_head *cnew,
        new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL);
        if (new->hostname) {
                new->namelen = key->namelen;
-               memcpy(&new->addr, &key->addr, key->addrlen);
-               new->addrlen = key->addrlen;
+               nfs_dns_ent_update(cnew, ckey);
        } else {
                new->namelen = 0;
                new->addrlen = 0;
@@ -234,7 +246,7 @@ static struct cache_detail nfs_dns_resolve = {
        .cache_show = nfs_dns_show,
        .match = nfs_dns_match,
        .init = nfs_dns_ent_init,
-       .update = nfs_dns_ent_init,
+       .update = nfs_dns_ent_update,
        .alloc = nfs_dns_ent_alloc,
 };