aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/percpu_ida.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/lib/percpu_ida.c b/lib/percpu_ida.c
index 9d054bf91d0f..7be235f1a70b 100644
--- a/lib/percpu_ida.c
+++ b/lib/percpu_ida.c
@@ -132,22 +132,22 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
132/** 132/**
133 * percpu_ida_alloc - allocate a tag 133 * percpu_ida_alloc - allocate a tag
134 * @pool: pool to allocate from 134 * @pool: pool to allocate from
135 * @gfp: gfp flags 135 * @state: task state for prepare_to_wait
136 * 136 *
137 * Returns a tag - an integer in the range [0..nr_tags) (passed to 137 * Returns a tag - an integer in the range [0..nr_tags) (passed to
138 * tag_pool_init()), or otherwise -ENOSPC on allocation failure. 138 * tag_pool_init()), or otherwise -ENOSPC on allocation failure.
139 * 139 *
140 * Safe to be called from interrupt context (assuming it isn't passed 140 * Safe to be called from interrupt context (assuming it isn't passed
141 * __GFP_WAIT, of course). 141 * TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course).
142 * 142 *
143 * @gfp indicates whether or not to wait until a free id is available (it's not 143 * @gfp indicates whether or not to wait until a free id is available (it's not
144 * used for internal memory allocations); thus if passed __GFP_WAIT we may sleep 144 * used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
145 * however long it takes until another thread frees an id (same semantics as a 145 * however long it takes until another thread frees an id (same semantics as a
146 * mempool). 146 * mempool).
147 * 147 *
148 * Will not fail if passed __GFP_WAIT. 148 * Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE.
149 */ 149 */
150int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp) 150int percpu_ida_alloc(struct percpu_ida *pool, int state)
151{ 151{
152 DEFINE_WAIT(wait); 152 DEFINE_WAIT(wait);
153 struct percpu_ida_cpu *tags; 153 struct percpu_ida_cpu *tags;
@@ -174,7 +174,8 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
174 * 174 *
175 * global lock held and irqs disabled, don't need percpu lock 175 * global lock held and irqs disabled, don't need percpu lock
176 */ 176 */
177 prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); 177 if (state != TASK_RUNNING)
178 prepare_to_wait(&pool->wait, &wait, state);
178 179
179 if (!tags->nr_free) 180 if (!tags->nr_free)
180 alloc_global_tags(pool, tags); 181 alloc_global_tags(pool, tags);
@@ -191,16 +192,22 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
191 spin_unlock(&pool->lock); 192 spin_unlock(&pool->lock);
192 local_irq_restore(flags); 193 local_irq_restore(flags);
193 194
194 if (tag >= 0 || !(gfp & __GFP_WAIT)) 195 if (tag >= 0 || state == TASK_RUNNING)
195 break; 196 break;
196 197
198 if (signal_pending_state(state, current)) {
199 tag = -ERESTARTSYS;
200 break;
201 }
202
197 schedule(); 203 schedule();
198 204
199 local_irq_save(flags); 205 local_irq_save(flags);
200 tags = this_cpu_ptr(pool->tag_cpu); 206 tags = this_cpu_ptr(pool->tag_cpu);
201 } 207 }
208 if (state != TASK_RUNNING)
209 finish_wait(&pool->wait, &wait);
202 210
203 finish_wait(&pool->wait, &wait);
204 return tag; 211 return tag;
205} 212}
206EXPORT_SYMBOL_GPL(percpu_ida_alloc); 213EXPORT_SYMBOL_GPL(percpu_ida_alloc);