nfsd: fix cleanup of nfsd_reply_cache_init on failure
authorJ. Bruce Fields <bfields@redhat.com>
Wed, 5 Jun 2019 22:03:52 +0000 (18:03 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 3 Jul 2019 21:52:09 +0000 (17:52 -0400)
The failure to unregister the shrinker results will result in corruption
when the nfsd_net is freed.

Also clean up the drc_slab while we're here.

Reported-by: syzbot+83a43746cebef3508b49@syzkaller.appspotmail.com
Fixes: db17b61765c2 ("nfsd4: drc containerization")
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfscache.c

index b774306d128914dc20414aeb4bbc99e87f01beec..26ad75ae2be042d3372f3bea221a3af0787a4722 100644 (file)
@@ -157,12 +157,12 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
        nn->nfsd_reply_cache_shrinker.seeks = 1;
        status = register_shrinker(&nn->nfsd_reply_cache_shrinker);
        if (status)
-               return status;
+               goto out_nomem;
 
        nn->drc_slab = kmem_cache_create("nfsd_drc",
                                sizeof(struct svc_cacherep), 0, 0, NULL);
        if (!nn->drc_slab)
-               goto out_nomem;
+               goto out_shrinker;
 
        nn->drc_hashtbl = kcalloc(hashsize,
                                sizeof(*nn->drc_hashtbl), GFP_KERNEL);
@@ -170,7 +170,7 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
                nn->drc_hashtbl = vzalloc(array_size(hashsize,
                                                 sizeof(*nn->drc_hashtbl)));
                if (!nn->drc_hashtbl)
-                       goto out_nomem;
+                       goto out_slab;
        }
 
        for (i = 0; i < hashsize; i++) {
@@ -180,6 +180,10 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
        nn->drc_hashsize = hashsize;
 
        return 0;
+out_slab:
+       kmem_cache_destroy(nn->drc_slab);
+out_shrinker:
+       unregister_shrinker(&nn->nfsd_reply_cache_shrinker);
 out_nomem:
        printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
        return -ENOMEM;