Skip to content

Commit d69b78b

Browse files
gthelenJens Axboe
authored and
Jens Axboe
committed
ioprio: grab rcu_read_lock in sys_ioprio_{set,get}()
Using: - CONFIG_LOCKUP_DETECTOR=y - CONFIG_PREEMPT=y - CONFIG_LOCKDEP=y - CONFIG_PROVE_LOCKING=y - CONFIG_PROVE_RCU=y found a missing rcu lock during boot on a 512 MiB x86_64 ubuntu vm: =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- kernel/pid.c:419 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by ureadahead/1355: #0: (tasklist_lock){.+.+..}, at: [<ffffffff8115bc09>] sys_ioprio_set+0x7f/0x29e stack backtrace: Pid: 1355, comm: ureadahead Not tainted 2.6.37-dbg-DEV #1 Call Trace: [<ffffffff8109c10c>] lockdep_rcu_dereference+0xaa/0xb3 [<ffffffff81088cbf>] find_task_by_pid_ns+0x44/0x5d [<ffffffff81088cfa>] find_task_by_vpid+0x22/0x24 [<ffffffff8115bc3e>] sys_ioprio_set+0xb4/0x29e [<ffffffff8147cf21>] ? trace_hardirqs_off_thunk+0x3a/0x3c [<ffffffff8105c409>] sysenter_dispatch+0x7/0x2c [<ffffffff8147cee2>] ? trace_hardirqs_on_thunk+0x3a/0x3f The fix is to: a) grab rcu lock in sys_ioprio_{set,get}() and b) avoid grabbing tasklist_lock. Discussion in: http://marc.info/?l=linux-kernel&m=128951324702889 Signed-off-by: Greg Thelen <[email protected]> Acked-by: Paul E. McKenney <[email protected]> Reviewed-by: Oleg Nesterov <[email protected]> Modified by Jens to remove the now redundant inner rcu lock and unlock since they are now protected by the outer lock. Signed-off-by: Jens Axboe <[email protected]>
1 parent 1ff5125 commit d69b78b

File tree

1 file changed

+6
-25
lines changed

1 file changed

+6
-25
lines changed

fs/ioprio.c

+6-25
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,15 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
103103
}
104104

105105
ret = -ESRCH;
106-
/*
107-
* We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
108-
* so we can't use rcu_read_lock(). See re-copy of ->ioprio
109-
* in copy_process().
110-
*/
111-
read_lock(&tasklist_lock);
106+
rcu_read_lock();
112107
switch (which) {
113108
case IOPRIO_WHO_PROCESS:
114-
rcu_read_lock();
115109
if (!who)
116110
p = current;
117111
else
118112
p = find_task_by_vpid(who);
119113
if (p)
120114
ret = set_task_ioprio(p, ioprio);
121-
rcu_read_unlock();
122115
break;
123116
case IOPRIO_WHO_PGRP:
124117
if (!who)
@@ -141,12 +134,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
141134
break;
142135

143136
do_each_thread(g, p) {
144-
int match;
145-
146-
rcu_read_lock();
147-
match = __task_cred(p)->uid == who;
148-
rcu_read_unlock();
149-
if (!match)
137+
if (__task_cred(p)->uid != who)
150138
continue;
151139
ret = set_task_ioprio(p, ioprio);
152140
if (ret)
@@ -160,7 +148,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
160148
ret = -EINVAL;
161149
}
162150

163-
read_unlock(&tasklist_lock);
151+
rcu_read_unlock();
164152
return ret;
165153
}
166154

@@ -204,17 +192,15 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
204192
int ret = -ESRCH;
205193
int tmpio;
206194

207-
read_lock(&tasklist_lock);
195+
rcu_read_lock();
208196
switch (which) {
209197
case IOPRIO_WHO_PROCESS:
210-
rcu_read_lock();
211198
if (!who)
212199
p = current;
213200
else
214201
p = find_task_by_vpid(who);
215202
if (p)
216203
ret = get_task_ioprio(p);
217-
rcu_read_unlock();
218204
break;
219205
case IOPRIO_WHO_PGRP:
220206
if (!who)
@@ -241,12 +227,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
241227
break;
242228

243229
do_each_thread(g, p) {
244-
int match;
245-
246-
rcu_read_lock();
247-
match = __task_cred(p)->uid == user->uid;
248-
rcu_read_unlock();
249-
if (!match)
230+
if (__task_cred(p)->uid != user->uid)
250231
continue;
251232
tmpio = get_task_ioprio(p);
252233
if (tmpio < 0)
@@ -264,6 +245,6 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
264245
ret = -EINVAL;
265246
}
266247

267-
read_unlock(&tasklist_lock);
248+
rcu_read_unlock();
268249
return ret;
269250
}

0 commit comments

Comments
 (0)