Skip to content

Commit 6f6b5d1

Browse files
Kent OverstreetNicholas Bellinger
Kent Overstreet
authored and
Nicholas Bellinger
committed
percpu_ida: Make percpu_ida_alloc + callers accept task state bitmask
This patch changes percpu_ida_alloc() + callers to accept task state bitmask for prepare_to_wait() for code like target/iscsi that needs it for interruptible sleep, that is provided in a subsequent patch. It now expects TASK_UNINTERRUPTIBLE when the caller is able to sleep waiting for a new tag, or TASK_RUNNING when the caller cannot sleep, and is forced to return a negative value when no tags are available. v2 changes: - Include blk-mq + tcm_fc + vhost/scsi + target/iscsi changes - Drop signal_pending_state() call v3 changes: - Only call prepare_to_wait() + finish_wait() when != TASK_RUNNING (PeterZ) Reported-by: Linus Torvalds <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Jens Axboe <[email protected]> Signed-off-by: Kent Overstreet <[email protected]> Cc: <[email protected]> #3.12+ Signed-off-by: Nicholas Bellinger <[email protected]>
1 parent 4a4caa2 commit 6f6b5d1

File tree

6 files changed

+23
-14
lines changed

6 files changed

+23
-14
lines changed

block/blk-mq-tag.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp)
3636
{
3737
int tag;
3838

39-
tag = percpu_ida_alloc(&tags->free_tags, gfp);
39+
tag = percpu_ida_alloc(&tags->free_tags, (gfp & __GFP_WAIT) ?
40+
TASK_UNINTERRUPTIBLE : TASK_RUNNING);
4041
if (tag < 0)
4142
return BLK_MQ_TAG_FAIL;
4243
return tag + tags->nr_reserved_tags;
@@ -52,7 +53,8 @@ static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_tags *tags,
5253
return BLK_MQ_TAG_FAIL;
5354
}
5455

55-
tag = percpu_ida_alloc(&tags->reserved_tags, gfp);
56+
tag = percpu_ida_alloc(&tags->reserved_tags, (gfp & __GFP_WAIT) ?
57+
TASK_UNINTERRUPTIBLE : TASK_RUNNING);
5658
if (tag < 0)
5759
return BLK_MQ_TAG_FAIL;
5860
return tag;

drivers/target/iscsi/iscsi_target_util.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,13 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
156156
{
157157
struct iscsi_cmd *cmd;
158158
struct se_session *se_sess = conn->sess->se_sess;
159-
int size, tag;
159+
int size, tag, state = (gfp_mask & __GFP_WAIT) ? TASK_UNINTERRUPTIBLE :
160+
TASK_RUNNING;
161+
162+
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state);
163+
if (tag < 0)
164+
return NULL;
160165

161-
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask);
162166
size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
163167
cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size));
164168
memset(cmd, 0, size);

drivers/target/tcm_fc/tfc_cmd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
438438
struct se_session *se_sess = sess->se_sess;
439439
int tag;
440440

441-
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
441+
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
442442
if (tag < 0)
443443
goto busy;
444444

drivers/vhost/scsi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
728728
}
729729
se_sess = tv_nexus->tvn_se_sess;
730730

731-
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
731+
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
732732
if (tag < 0) {
733733
pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
734734
return ERR_PTR(-ENOMEM);

include/linux/percpu_ida.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/types.h>
55
#include <linux/bitops.h>
66
#include <linux/init.h>
7+
#include <linux/sched.h>
78
#include <linux/spinlock_types.h>
89
#include <linux/wait.h>
910
#include <linux/cpumask.h>
@@ -61,7 +62,7 @@ struct percpu_ida {
6162
/* Max size of percpu freelist, */
6263
#define IDA_DEFAULT_PCPU_SIZE ((IDA_DEFAULT_PCPU_BATCH_MOVE * 3) / 2)
6364

64-
int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp);
65+
int percpu_ida_alloc(struct percpu_ida *pool, int state);
6566
void percpu_ida_free(struct percpu_ida *pool, unsigned tag);
6667

6768
void percpu_ida_destroy(struct percpu_ida *pool);

lib/percpu_ida.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,22 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
132132
/**
133133
* percpu_ida_alloc - allocate a tag
134134
* @pool: pool to allocate from
135-
* @gfp: gfp flags
135+
* @state: task state for prepare_to_wait
136136
*
137137
* Returns a tag - an integer in the range [0..nr_tags) (passed to
138138
* tag_pool_init()), or otherwise -ENOSPC on allocation failure.
139139
*
140140
* Safe to be called from interrupt context (assuming it isn't passed
141-
* __GFP_WAIT, of course).
141+
* TASK_UNINTERRUPTIBLE, of course).
142142
*
143143
* @gfp indicates whether or not to wait until a free id is available (it's not
144144
* used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
145145
* however long it takes until another thread frees an id (same semantics as a
146146
* mempool).
147147
*
148-
* Will not fail if passed __GFP_WAIT.
148+
* Will not fail if passed TASK_UNINTERRUPTIBLE.
149149
*/
150-
int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
150+
int percpu_ida_alloc(struct percpu_ida *pool, int state)
151151
{
152152
DEFINE_WAIT(wait);
153153
struct percpu_ida_cpu *tags;
@@ -174,7 +174,8 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
174174
*
175175
* global lock held and irqs disabled, don't need percpu lock
176176
*/
177-
prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
177+
if (state != TASK_RUNNING)
178+
prepare_to_wait(&pool->wait, &wait, state);
178179

179180
if (!tags->nr_free)
180181
alloc_global_tags(pool, tags);
@@ -191,16 +192,17 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
191192
spin_unlock(&pool->lock);
192193
local_irq_restore(flags);
193194

194-
if (tag >= 0 || !(gfp & __GFP_WAIT))
195+
if (tag >= 0 || state == TASK_RUNNING)
195196
break;
196197

197198
schedule();
198199

199200
local_irq_save(flags);
200201
tags = this_cpu_ptr(pool->tag_cpu);
201202
}
203+
if (state != TASK_RUNNING)
204+
finish_wait(&pool->wait, &wait);
202205

203-
finish_wait(&pool->wait, &wait);
204206
return tag;
205207
}
206208
EXPORT_SYMBOL_GPL(percpu_ida_alloc);

0 commit comments

Comments
 (0)