Skip to content

Commit 515dcdc

Browse files
author
Trond Myklebust
committed
NFS: nfsiod should not block forever in mempool_alloc()
The concern is that since nfsiod is sometimes required to kick off a commit, it can get locked up waiting forever in mempool_alloc() instead of failing gracefully and leaving the commit until later. Try to allocate from the slab first, with GFP_KERNEL | __GFP_NORETRY, then fall back to a non-blocking attempt to allocate from the memory pool. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent b264801 commit 515dcdc

4 files changed

Lines changed: 23 additions & 18 deletions

File tree

fs/nfs/internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,13 @@ nfs_write_match_verf(const struct nfs_writeverf *verf,
587587
!nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier);
588588
}
589589

590+
static inline gfp_t nfs_io_gfp_mask(void)
591+
{
592+
if (current->flags & PF_WQ_WORKER)
593+
return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
594+
return GFP_KERNEL;
595+
}
596+
590597
/* unlink.c */
591598
extern struct rpc_task *
592599
nfs_async_rename(struct inode *old_dir, struct inode *new_dir,

fs/nfs/pnfs_nfs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ static struct nfs_commit_data *
419419
pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
420420
struct nfs_commit_info *cinfo)
421421
{
422-
struct nfs_commit_data *data = nfs_commitdata_alloc(false);
422+
struct nfs_commit_data *data = nfs_commitdata_alloc();
423423

424424
if (!data)
425425
return NULL;
@@ -515,7 +515,11 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
515515
unsigned int nreq = 0;
516516

517517
if (!list_empty(mds_pages)) {
518-
data = nfs_commitdata_alloc(true);
518+
data = nfs_commitdata_alloc();
519+
if (!data) {
520+
nfs_retry_commit(mds_pages, NULL, cinfo, -1);
521+
return -ENOMEM;
522+
}
519523
data->ds_commit_index = -1;
520524
list_splice_init(mds_pages, &data->pages);
521525
list_add_tail(&data->list, &list);

fs/nfs/write.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,17 @@ static mempool_t *nfs_wdata_mempool;
7070
static struct kmem_cache *nfs_cdata_cachep;
7171
static mempool_t *nfs_commit_mempool;
7272

73-
struct nfs_commit_data *nfs_commitdata_alloc(bool never_fail)
73+
struct nfs_commit_data *nfs_commitdata_alloc(void)
7474
{
7575
struct nfs_commit_data *p;
7676

77-
if (never_fail)
78-
p = mempool_alloc(nfs_commit_mempool, GFP_NOIO);
79-
else {
80-
/* It is OK to do some reclaim, not no safe to wait
81-
* for anything to be returned to the pool.
82-
* mempool_alloc() cannot handle that particular combination,
83-
* so we need two separate attempts.
84-
*/
77+
p = kmem_cache_zalloc(nfs_cdata_cachep, nfs_io_gfp_mask());
78+
if (!p) {
8579
p = mempool_alloc(nfs_commit_mempool, GFP_NOWAIT);
86-
if (!p)
87-
p = kmem_cache_alloc(nfs_cdata_cachep, GFP_NOIO |
88-
__GFP_NOWARN | __GFP_NORETRY);
8980
if (!p)
9081
return NULL;
82+
memset(p, 0, sizeof(*p));
9183
}
92-
93-
memset(p, 0, sizeof(*p));
9484
INIT_LIST_HEAD(&p->pages);
9585
return p;
9686
}
@@ -1826,7 +1816,11 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
18261816
if (list_empty(head))
18271817
return 0;
18281818

1829-
data = nfs_commitdata_alloc(true);
1819+
data = nfs_commitdata_alloc();
1820+
if (!data) {
1821+
nfs_retry_commit(head, NULL, cinfo, -1);
1822+
return -ENOMEM;
1823+
}
18301824

18311825
/* Set up the argument struct */
18321826
nfs_init_commit(data, head, NULL, cinfo);

include/linux/nfs_fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ extern int nfs_wb_all(struct inode *inode);
580580
extern int nfs_wb_page(struct inode *inode, struct page *page);
581581
extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
582582
extern int nfs_commit_inode(struct inode *, int);
583-
extern struct nfs_commit_data *nfs_commitdata_alloc(bool never_fail);
583+
extern struct nfs_commit_data *nfs_commitdata_alloc(void);
584584
extern void nfs_commit_free(struct nfs_commit_data *data);
585585
bool nfs_commit_end(struct nfs_mds_commit_info *cinfo);
586586

0 commit comments

Comments
 (0)