]> git.baikalelectronics.ru Git - kernel.git/commitdiff
NFS: Reduce readdir stack usage
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 2 Nov 2020 13:55:03 +0000 (08:55 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
The descriptor and the struct nfs_entry are both large structures,
so don't allocate them from the stack.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
fs/nfs/dir.c

index 48856cee10ded8059640a3a4970dd26f61197dbe..c3af54640f6cd84565f0eaa5fd6cbef4e8557445 100644 (file)
@@ -761,23 +761,24 @@ static
 int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
 {
        struct page **pages;
-       struct nfs_entry entry;
+       struct nfs_entry *entry;
        size_t array_size;
        size_t dtsize = NFS_SERVER(inode)->dtsize;
        int status = -ENOMEM;
 
-       entry.prev_cookie = 0;
-       entry.cookie = nfs_readdir_page_last_cookie(page);
-       entry.eof = 0;
-       entry.fh = nfs_alloc_fhandle();
-       entry.fattr = nfs_alloc_fattr();
-       entry.server = NFS_SERVER(inode);
-       if (entry.fh == NULL || entry.fattr == NULL)
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+       entry->cookie = nfs_readdir_page_last_cookie(page);
+       entry->fh = nfs_alloc_fhandle();
+       entry->fattr = nfs_alloc_fattr();
+       entry->server = NFS_SERVER(inode);
+       if (entry->fh == NULL || entry->fattr == NULL)
                goto out;
 
-       entry.label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
-       if (IS_ERR(entry.label)) {
-               status = PTR_ERR(entry.label);
+       entry->label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
+       if (IS_ERR(entry->label)) {
+               status = PTR_ERR(entry->label);
                goto out;
        }
 
@@ -788,7 +789,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
 
        do {
                unsigned int pglen;
-               status = nfs_readdir_xdr_filler(desc, entry.cookie,
+               status = nfs_readdir_xdr_filler(desc, entry->cookie,
                                                pages, dtsize);
                if (status < 0)
                        break;
@@ -799,15 +800,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
                        break;
                }
 
-               status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
+               status = nfs_readdir_page_filler(desc, entry, pages, page, pglen);
        } while (!status && nfs_readdir_page_needs_filling(page));
 
        nfs_readdir_free_pages(pages, array_size);
 out_release_label:
-       nfs4_label_free(entry.label);
+       nfs4_label_free(entry->label);
 out:
-       nfs_free_fattr(entry.fattr);
-       nfs_free_fhandle(entry.fh);
+       nfs_free_fattr(entry->fattr);
+       nfs_free_fhandle(entry->fh);
+       kfree(entry);
        return status;
 }
 
@@ -974,13 +976,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        struct dentry   *dentry = file_dentry(file);
        struct inode    *inode = d_inode(dentry);
        struct nfs_open_dir_context *dir_ctx = file->private_data;
-       nfs_readdir_descriptor_t my_desc = {
-               .file = file,
-               .ctx = ctx,
-               .plus = nfs_use_readdirplus(inode, ctx),
-       },
-                       *desc = &my_desc;
-       int res = 0;
+       struct nfs_readdir_descriptor *desc;
+       int res;
 
        dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n",
                        file, (long long)ctx->pos);
@@ -992,10 +989,19 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
         * to either find the entry with the appropriate number or
         * revalidate the cookie.
         */
-       if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
+       if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) {
                res = nfs_revalidate_mapping(inode, file->f_mapping);
-       if (res < 0)
+               if (res < 0)
+                       goto out;
+       }
+
+       res = -ENOMEM;
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
                goto out;
+       desc->file = file;
+       desc->ctx = ctx;
+       desc->plus = nfs_use_readdirplus(inode, ctx);
 
        spin_lock(&file->f_lock);
        desc->dir_cookie = dir_ctx->dir_cookie;
@@ -1040,6 +1046,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        dir_ctx->attr_gencount = desc->attr_gencount;
        spin_unlock(&file->f_lock);
 
+       kfree(desc);
+
 out:
        dfprintk(FILE, "NFS: readdir(%pD2) returns %d\n", file, res);
        return res;