Skip to content

Commit d9f85a0

Browse files
committed
netfs: Use mempools for allocating requests and subrequests
Use mempools for allocating requests and subrequests in an effort to make sure that allocation always succeeds so that when performing writeback we can always make progress. Signed-off-by: David Howells <[email protected]> Reviewed-by: Jeff Layton <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected]
1 parent b4ff7b1 commit d9f85a0

File tree

4 files changed

+89
-28
lines changed

4 files changed

+89
-28
lines changed

fs/netfs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync);
3737
extern unsigned int netfs_debug;
3838
extern struct list_head netfs_io_requests;
3939
extern spinlock_t netfs_proc_lock;
40+
extern mempool_t netfs_request_pool;
41+
extern mempool_t netfs_subrequest_pool;
4042

4143
#ifdef CONFIG_PROC_FS
4244
static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq)

fs/netfs/main.c

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/module.h>
99
#include <linux/export.h>
10+
#include <linux/mempool.h>
1011
#include <linux/proc_fs.h>
1112
#include <linux/seq_file.h>
1213
#include "internal.h"
@@ -23,6 +24,11 @@ unsigned netfs_debug;
2324
module_param_named(debug, netfs_debug, uint, S_IWUSR | S_IRUGO);
2425
MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask");
2526

27+
static struct kmem_cache *netfs_request_slab;
28+
static struct kmem_cache *netfs_subrequest_slab;
29+
mempool_t netfs_request_pool;
30+
mempool_t netfs_subrequest_pool;
31+
2632
#ifdef CONFIG_PROC_FS
2733
LIST_HEAD(netfs_io_requests);
2834
DEFINE_SPINLOCK(netfs_proc_lock);
@@ -98,25 +104,54 @@ static int __init netfs_init(void)
98104
{
99105
int ret = -ENOMEM;
100106

107+
netfs_request_slab = kmem_cache_create("netfs_request",
108+
sizeof(struct netfs_io_request), 0,
109+
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT,
110+
NULL);
111+
if (!netfs_request_slab)
112+
goto error_req;
113+
114+
if (mempool_init_slab_pool(&netfs_request_pool, 100, netfs_request_slab) < 0)
115+
goto error_reqpool;
116+
117+
netfs_subrequest_slab = kmem_cache_create("netfs_subrequest",
118+
sizeof(struct netfs_io_subrequest), 0,
119+
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT,
120+
NULL);
121+
if (!netfs_subrequest_slab)
122+
goto error_subreq;
123+
124+
if (mempool_init_slab_pool(&netfs_subrequest_pool, 100, netfs_subrequest_slab) < 0)
125+
goto error_subreqpool;
126+
101127
if (!proc_mkdir("fs/netfs", NULL))
102-
goto error;
128+
goto error_proc;
103129
if (!proc_create_seq("fs/netfs/requests", S_IFREG | 0444, NULL,
104130
&netfs_requests_seq_ops))
105-
goto error_proc;
131+
goto error_procfile;
106132
#ifdef CONFIG_FSCACHE_STATS
107133
if (!proc_create_single("fs/netfs/stats", S_IFREG | 0444, NULL,
108134
netfs_stats_show))
109-
goto error_proc;
135+
goto error_procfile;
110136
#endif
111137

112138
ret = fscache_init();
113139
if (ret < 0)
114-
goto error_proc;
140+
goto error_fscache;
115141
return 0;
116142

117-
error_proc:
143+
error_fscache:
144+
error_procfile:
118145
remove_proc_entry("fs/netfs", NULL);
119-
error:
146+
error_proc:
147+
mempool_exit(&netfs_subrequest_pool);
148+
error_subreqpool:
149+
kmem_cache_destroy(netfs_subrequest_slab);
150+
error_subreq:
151+
mempool_exit(&netfs_request_pool);
152+
error_reqpool:
153+
kmem_cache_destroy(netfs_request_slab);
154+
error_req:
120155
return ret;
121156
}
122157
fs_initcall(netfs_init);
@@ -125,5 +160,9 @@ static void __exit netfs_exit(void)
125160
{
126161
fscache_exit();
127162
remove_proc_entry("fs/netfs", NULL);
163+
mempool_exit(&netfs_subrequest_pool);
164+
kmem_cache_destroy(netfs_subrequest_slab);
165+
mempool_exit(&netfs_request_pool);
166+
kmem_cache_destroy(netfs_request_slab);
128167
}
129168
module_exit(netfs_exit);

fs/netfs/objects.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77

88
#include <linux/slab.h>
9+
#include <linux/mempool.h>
10+
#include <linux/delay.h>
911
#include "internal.h"
1012

1113
/*
@@ -20,17 +22,22 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
2022
struct inode *inode = file ? file_inode(file) : mapping->host;
2123
struct netfs_inode *ctx = netfs_inode(inode);
2224
struct netfs_io_request *rreq;
25+
mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool;
26+
struct kmem_cache *cache = mempool->pool_data;
2327
bool is_unbuffered = (origin == NETFS_UNBUFFERED_WRITE ||
2428
origin == NETFS_DIO_READ ||
2529
origin == NETFS_DIO_WRITE);
2630
bool cached = !is_unbuffered && netfs_is_cache_enabled(ctx);
2731
int ret;
2832

29-
rreq = kzalloc(ctx->ops->io_request_size ?: sizeof(struct netfs_io_request),
30-
GFP_KERNEL);
31-
if (!rreq)
32-
return ERR_PTR(-ENOMEM);
33+
for (;;) {
34+
rreq = mempool_alloc(mempool, GFP_KERNEL);
35+
if (rreq)
36+
break;
37+
msleep(10);
38+
}
3339

40+
memset(rreq, 0, kmem_cache_size(cache));
3441
rreq->start = start;
3542
rreq->len = len;
3643
rreq->upper_len = len;
@@ -56,7 +63,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
5663
if (rreq->netfs_ops->init_request) {
5764
ret = rreq->netfs_ops->init_request(rreq, file);
5865
if (ret < 0) {
59-
kfree(rreq);
66+
mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
6067
return ERR_PTR(ret);
6168
}
6269
}
@@ -88,6 +95,14 @@ void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)
8895
}
8996
}
9097

98+
static void netfs_free_request_rcu(struct rcu_head *rcu)
99+
{
100+
struct netfs_io_request *rreq = container_of(rcu, struct netfs_io_request, rcu);
101+
102+
mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
103+
netfs_stat_d(&netfs_n_rh_rreq);
104+
}
105+
91106
static void netfs_free_request(struct work_struct *work)
92107
{
93108
struct netfs_io_request *rreq =
@@ -110,8 +125,7 @@ static void netfs_free_request(struct work_struct *work)
110125
}
111126
kvfree(rreq->direct_bv);
112127
}
113-
kfree_rcu(rreq, rcu);
114-
netfs_stat_d(&netfs_n_rh_rreq);
128+
call_rcu(&rreq->rcu, netfs_free_request_rcu);
115129
}
116130

117131
void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
@@ -143,20 +157,25 @@ void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
143157
struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq)
144158
{
145159
struct netfs_io_subrequest *subreq;
146-
147-
subreq = kzalloc(rreq->netfs_ops->io_subrequest_size ?:
148-
sizeof(struct netfs_io_subrequest),
149-
GFP_KERNEL);
150-
if (subreq) {
151-
INIT_WORK(&subreq->work, NULL);
152-
INIT_LIST_HEAD(&subreq->rreq_link);
153-
refcount_set(&subreq->ref, 2);
154-
subreq->rreq = rreq;
155-
subreq->debug_index = atomic_inc_return(&rreq->subreq_counter);
156-
netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
157-
netfs_stat(&netfs_n_rh_sreq);
160+
mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool;
161+
struct kmem_cache *cache = mempool->pool_data;
162+
163+
for (;;) {
164+
subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool,
165+
GFP_KERNEL);
166+
if (subreq)
167+
break;
168+
msleep(10);
158169
}
159170

171+
memset(subreq, 0, kmem_cache_size(cache));
172+
INIT_WORK(&subreq->work, NULL);
173+
INIT_LIST_HEAD(&subreq->rreq_link);
174+
refcount_set(&subreq->ref, 2);
175+
subreq->rreq = rreq;
176+
subreq->debug_index = atomic_inc_return(&rreq->subreq_counter);
177+
netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
178+
netfs_stat(&netfs_n_rh_sreq);
160179
return subreq;
161180
}
162181

@@ -178,7 +197,7 @@ static void netfs_free_subrequest(struct netfs_io_subrequest *subreq,
178197
trace_netfs_sreq(subreq, netfs_sreq_trace_free);
179198
if (rreq->netfs_ops->free_subrequest)
180199
rreq->netfs_ops->free_subrequest(subreq);
181-
kfree(subreq);
200+
mempool_free(subreq, rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool);
182201
netfs_stat_d(&netfs_n_rh_sreq);
183202
netfs_put_request(rreq, was_async, netfs_rreq_trace_put_subreq);
184203
}

include/linux/netfs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/uio.h>
2121

2222
enum netfs_sreq_ref_trace;
23+
typedef struct mempool_s mempool_t;
2324

2425
/**
2526
* folio_start_private_2 - Start an fscache write on a folio. [DEPRECATED]
@@ -236,8 +237,8 @@ struct netfs_io_request {
236237
* Operations the network filesystem can/must provide to the helpers.
237238
*/
238239
struct netfs_request_ops {
239-
unsigned int io_request_size; /* Alloc size for netfs_io_request struct */
240-
unsigned int io_subrequest_size; /* Alloc size for netfs_io_subrequest struct */
240+
mempool_t *request_pool;
241+
mempool_t *subrequest_pool;
241242
int (*init_request)(struct netfs_io_request *rreq, struct file *file);
242243
void (*free_request)(struct netfs_io_request *rreq);
243244
void (*free_subrequest)(struct netfs_io_subrequest *rreq);

0 commit comments

Comments
 (0)