blob: 8bf4c57dba5cbaa7035c2688b29662ce4bd3d178 [file] [log] [blame]
jinqian69014222015-03-11 10:44:50 -07001/* drivers/misc/uid_cputime.c
2 *
3 * Copyright (C) 2014 - 2015 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/atomic.h>
17#include <linux/err.h>
18#include <linux/hashtable.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/list.h>
22#include <linux/proc_fs.h>
23#include <linux/profile.h>
Wei Wang7f1ad082017-03-13 12:22:21 -070024#include <linux/rtmutex.h>
jinqian69014222015-03-11 10:44:50 -070025#include <linux/sched.h>
26#include <linux/seq_file.h>
27#include <linux/slab.h>
28#include <linux/uaccess.h>
29
Wei Wang7f1ad082017-03-13 12:22:21 -070030
jinqian69014222015-03-11 10:44:50 -070031#define UID_HASH_BITS 10
32DECLARE_HASHTABLE(hash_table, UID_HASH_BITS);
33
Wei Wang7f1ad082017-03-13 12:22:21 -070034static DEFINE_RT_MUTEX(uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -080035static struct proc_dir_entry *cpu_parent;
36static struct proc_dir_entry *io_parent;
37static struct proc_dir_entry *proc_parent;
38
39struct io_stats {
40 u64 read_bytes;
41 u64 write_bytes;
42 u64 rchar;
43 u64 wchar;
Jin Qian62eb9f92017-03-02 13:39:43 -080044 u64 fsync;
Jin Qian012f2002017-01-10 16:10:35 -080045};
46
47#define UID_STATE_FOREGROUND 0
48#define UID_STATE_BACKGROUND 1
49#define UID_STATE_BUCKET_SIZE 2
50
51#define UID_STATE_TOTAL_CURR 2
52#define UID_STATE_TOTAL_LAST 3
Jin Qiancd5e19c2017-05-22 12:08:06 -070053#define UID_STATE_DEAD_TASKS 4
54#define UID_STATE_SIZE 5
jinqian69014222015-03-11 10:44:50 -070055
56struct uid_entry {
57 uid_t uid;
58 cputime_t utime;
59 cputime_t stime;
60 cputime_t active_utime;
61 cputime_t active_stime;
Jin Qian012f2002017-01-10 16:10:35 -080062 int state;
63 struct io_stats io[UID_STATE_SIZE];
jinqian69014222015-03-11 10:44:50 -070064 struct hlist_node hash;
65};
66
67static struct uid_entry *find_uid_entry(uid_t uid)
68{
69 struct uid_entry *uid_entry;
70 hash_for_each_possible(hash_table, uid_entry, hash, uid) {
71 if (uid_entry->uid == uid)
72 return uid_entry;
73 }
74 return NULL;
75}
76
77static struct uid_entry *find_or_register_uid(uid_t uid)
78{
79 struct uid_entry *uid_entry;
80
81 uid_entry = find_uid_entry(uid);
82 if (uid_entry)
83 return uid_entry;
84
85 uid_entry = kzalloc(sizeof(struct uid_entry), GFP_ATOMIC);
86 if (!uid_entry)
87 return NULL;
88
89 uid_entry->uid = uid;
90
91 hash_add(hash_table, &uid_entry->hash, uid);
92
93 return uid_entry;
94}
95
Jin Qian012f2002017-01-10 16:10:35 -080096static int uid_cputime_show(struct seq_file *m, void *v)
jinqian69014222015-03-11 10:44:50 -070097{
Ganesh Mahendran2b3da4a2017-05-25 15:20:29 +080098 struct uid_entry *uid_entry = NULL;
Ruchi Kandoi0a733772015-07-31 10:17:54 -070099 struct task_struct *task, *temp;
Ganesh Mahendrane6ef73f2017-04-25 18:07:43 +0800100 struct user_namespace *user_ns = current_user_ns();
jinqian69014222015-03-11 10:44:50 -0700101 cputime_t utime;
102 cputime_t stime;
103 unsigned long bkt;
Ganesh Mahendrane6ef73f2017-04-25 18:07:43 +0800104 uid_t uid;
jinqian69014222015-03-11 10:44:50 -0700105
Wei Wang7f1ad082017-03-13 12:22:21 -0700106 rt_mutex_lock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700107
108 hash_for_each(hash_table, bkt, uid_entry, hash) {
109 uid_entry->active_stime = 0;
110 uid_entry->active_utime = 0;
111 }
112
113 read_lock(&tasklist_lock);
Ruchi Kandoi0a733772015-07-31 10:17:54 -0700114 do_each_thread(temp, task) {
Ganesh Mahendrane6ef73f2017-04-25 18:07:43 +0800115 uid = from_kuid_munged(user_ns, task_uid(task));
Ganesh Mahendran2b3da4a2017-05-25 15:20:29 +0800116 if (!uid_entry || uid_entry->uid != uid)
117 uid_entry = find_or_register_uid(uid);
jinqian69014222015-03-11 10:44:50 -0700118 if (!uid_entry) {
119 read_unlock(&tasklist_lock);
Wei Wang7f1ad082017-03-13 12:22:21 -0700120 rt_mutex_unlock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700121 pr_err("%s: failed to find the uid_entry for uid %d\n",
Ganesh Mahendrane6ef73f2017-04-25 18:07:43 +0800122 __func__, uid);
jinqian69014222015-03-11 10:44:50 -0700123 return -ENOMEM;
124 }
125 task_cputime_adjusted(task, &utime, &stime);
126 uid_entry->active_utime += utime;
127 uid_entry->active_stime += stime;
Ruchi Kandoi0a733772015-07-31 10:17:54 -0700128 } while_each_thread(temp, task);
jinqian69014222015-03-11 10:44:50 -0700129 read_unlock(&tasklist_lock);
130
131 hash_for_each(hash_table, bkt, uid_entry, hash) {
132 cputime_t total_utime = uid_entry->utime +
133 uid_entry->active_utime;
134 cputime_t total_stime = uid_entry->stime +
135 uid_entry->active_stime;
Amit Pundire4395b22015-12-14 11:56:35 +0530136 seq_printf(m, "%d: %llu %llu\n", uid_entry->uid,
Jin Qianbe7074f2015-07-13 18:16:55 -0700137 (unsigned long long)jiffies_to_msecs(
138 cputime_to_jiffies(total_utime)) * USEC_PER_MSEC,
139 (unsigned long long)jiffies_to_msecs(
Amit Pundire4395b22015-12-14 11:56:35 +0530140 cputime_to_jiffies(total_stime)) * USEC_PER_MSEC);
jinqian69014222015-03-11 10:44:50 -0700141 }
142
Wei Wang7f1ad082017-03-13 12:22:21 -0700143 rt_mutex_unlock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700144 return 0;
145}
146
Jin Qian012f2002017-01-10 16:10:35 -0800147static int uid_cputime_open(struct inode *inode, struct file *file)
jinqian69014222015-03-11 10:44:50 -0700148{
Jin Qian012f2002017-01-10 16:10:35 -0800149 return single_open(file, uid_cputime_show, PDE_DATA(inode));
jinqian69014222015-03-11 10:44:50 -0700150}
151
Jin Qian012f2002017-01-10 16:10:35 -0800152static const struct file_operations uid_cputime_fops = {
153 .open = uid_cputime_open,
jinqian69014222015-03-11 10:44:50 -0700154 .read = seq_read,
155 .llseek = seq_lseek,
156 .release = single_release,
157};
158
159static int uid_remove_open(struct inode *inode, struct file *file)
160{
161 return single_open(file, NULL, NULL);
162}
163
164static ssize_t uid_remove_write(struct file *file,
165 const char __user *buffer, size_t count, loff_t *ppos)
166{
167 struct uid_entry *uid_entry;
168 struct hlist_node *tmp;
169 char uids[128];
170 char *start_uid, *end_uid = NULL;
171 long int uid_start = 0, uid_end = 0;
172
173 if (count >= sizeof(uids))
174 count = sizeof(uids) - 1;
175
176 if (copy_from_user(uids, buffer, count))
177 return -EFAULT;
178
179 uids[count] = '\0';
180 end_uid = uids;
181 start_uid = strsep(&end_uid, "-");
182
183 if (!start_uid || !end_uid)
184 return -EINVAL;
185
186 if (kstrtol(start_uid, 10, &uid_start) != 0 ||
187 kstrtol(end_uid, 10, &uid_end) != 0) {
188 return -EINVAL;
189 }
Wei Wang7f1ad082017-03-13 12:22:21 -0700190 rt_mutex_lock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700191
192 for (; uid_start <= uid_end; uid_start++) {
193 hash_for_each_possible_safe(hash_table, uid_entry, tmp,
Ruchi Kandoi17f35ea2015-10-23 17:49:11 -0700194 hash, (uid_t)uid_start) {
195 if (uid_start == uid_entry->uid) {
196 hash_del(&uid_entry->hash);
197 kfree(uid_entry);
198 }
jinqian69014222015-03-11 10:44:50 -0700199 }
200 }
201
Wei Wang7f1ad082017-03-13 12:22:21 -0700202 rt_mutex_unlock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700203 return count;
204}
205
206static const struct file_operations uid_remove_fops = {
207 .open = uid_remove_open,
208 .release = single_release,
209 .write = uid_remove_write,
210};
211
Jin Qian5c837b92017-02-28 15:09:42 -0800212static u64 compute_write_bytes(struct task_struct *task)
213{
214 if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
215 return 0;
216
217 return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
218}
219
Jin Qiancd5e19c2017-05-22 12:08:06 -0700220static void add_uid_io_stats(struct uid_entry *uid_entry,
221 struct task_struct *task, int slot)
Jin Qian012f2002017-01-10 16:10:35 -0800222{
Jin Qiancd5e19c2017-05-22 12:08:06 -0700223 struct io_stats *io_slot = &uid_entry->io[slot];
Jin Qian012f2002017-01-10 16:10:35 -0800224
Jin Qiancd5e19c2017-05-22 12:08:06 -0700225 io_slot->read_bytes += task->ioac.read_bytes;
226 io_slot->write_bytes += compute_write_bytes(task);
227 io_slot->rchar += task->ioac.rchar;
228 io_slot->wchar += task->ioac.wchar;
229 io_slot->fsync += task->ioac.syscfs;
Jin Qian012f2002017-01-10 16:10:35 -0800230}
231
Jin Qiancd5e19c2017-05-22 12:08:06 -0700232static void compute_uid_io_bucket_stats(struct io_stats *io_bucket,
233 struct io_stats *io_curr,
234 struct io_stats *io_last,
235 struct io_stats *io_dead)
Jin Qian012f2002017-01-10 16:10:35 -0800236{
Jin Qiancd5e19c2017-05-22 12:08:06 -0700237 io_bucket->read_bytes += io_curr->read_bytes + io_dead->read_bytes -
238 io_last->read_bytes;
239 io_bucket->write_bytes += io_curr->write_bytes + io_dead->write_bytes -
240 io_last->write_bytes;
241 io_bucket->rchar += io_curr->rchar + io_dead->rchar - io_last->rchar;
242 io_bucket->wchar += io_curr->wchar + io_dead->wchar - io_last->wchar;
243 io_bucket->fsync += io_curr->fsync + io_dead->fsync - io_last->fsync;
Jin Qian012f2002017-01-10 16:10:35 -0800244
Jin Qiancd5e19c2017-05-22 12:08:06 -0700245 io_last->read_bytes = io_curr->read_bytes;
246 io_last->write_bytes = io_curr->write_bytes;
247 io_last->rchar = io_curr->rchar;
248 io_last->wchar = io_curr->wchar;
249 io_last->fsync = io_curr->fsync;
250
251 memset(io_dead, 0, sizeof(struct io_stats));
Jin Qian012f2002017-01-10 16:10:35 -0800252}
253
Jin Qian67f252c2017-04-13 17:07:58 -0700254static void update_io_stats_all_locked(void)
Jin Qian012f2002017-01-10 16:10:35 -0800255{
Ganesh Mahendran2b3da4a2017-05-25 15:20:29 +0800256 struct uid_entry *uid_entry = NULL;
Jin Qian012f2002017-01-10 16:10:35 -0800257 struct task_struct *task, *temp;
Jin Qian67f252c2017-04-13 17:07:58 -0700258 struct user_namespace *user_ns = current_user_ns();
Jin Qian012f2002017-01-10 16:10:35 -0800259 unsigned long bkt;
Jin Qian67f252c2017-04-13 17:07:58 -0700260 uid_t uid;
Jin Qian012f2002017-01-10 16:10:35 -0800261
262 hash_for_each(hash_table, bkt, uid_entry, hash)
263 memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
264 sizeof(struct io_stats));
265
Jin Qian67f252c2017-04-13 17:07:58 -0700266 rcu_read_lock();
Jin Qian012f2002017-01-10 16:10:35 -0800267 do_each_thread(temp, task) {
Jin Qian67f252c2017-04-13 17:07:58 -0700268 uid = from_kuid_munged(user_ns, task_uid(task));
Ganesh Mahendran2b3da4a2017-05-25 15:20:29 +0800269 if (!uid_entry || uid_entry->uid != uid)
270 uid_entry = find_or_register_uid(uid);
Jin Qian012f2002017-01-10 16:10:35 -0800271 if (!uid_entry)
272 continue;
Jin Qiancd5e19c2017-05-22 12:08:06 -0700273 add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR);
Jin Qian012f2002017-01-10 16:10:35 -0800274 } while_each_thread(temp, task);
Jin Qian67f252c2017-04-13 17:07:58 -0700275 rcu_read_unlock();
Jin Qian012f2002017-01-10 16:10:35 -0800276
277 hash_for_each(hash_table, bkt, uid_entry, hash) {
Jin Qiancd5e19c2017-05-22 12:08:06 -0700278 compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
279 &uid_entry->io[UID_STATE_TOTAL_CURR],
280 &uid_entry->io[UID_STATE_TOTAL_LAST],
281 &uid_entry->io[UID_STATE_DEAD_TASKS]);
Jin Qian012f2002017-01-10 16:10:35 -0800282 }
283}
284
Jin Qiancd5e19c2017-05-22 12:08:06 -0700285static void update_io_stats_uid_locked(struct uid_entry *uid_entry)
Jin Qian67f252c2017-04-13 17:07:58 -0700286{
Jin Qian67f252c2017-04-13 17:07:58 -0700287 struct task_struct *task, *temp;
Jin Qian67f252c2017-04-13 17:07:58 -0700288 struct user_namespace *user_ns = current_user_ns();
289
Jin Qian67f252c2017-04-13 17:07:58 -0700290 memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
291 sizeof(struct io_stats));
292
293 rcu_read_lock();
294 do_each_thread(temp, task) {
Jin Qiancd5e19c2017-05-22 12:08:06 -0700295 if (from_kuid_munged(user_ns, task_uid(task)) != uid_entry->uid)
Jin Qian67f252c2017-04-13 17:07:58 -0700296 continue;
Jin Qiancd5e19c2017-05-22 12:08:06 -0700297 add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR);
Jin Qian67f252c2017-04-13 17:07:58 -0700298 } while_each_thread(temp, task);
299 rcu_read_unlock();
300
Jin Qiancd5e19c2017-05-22 12:08:06 -0700301 compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
302 &uid_entry->io[UID_STATE_TOTAL_CURR],
303 &uid_entry->io[UID_STATE_TOTAL_LAST],
304 &uid_entry->io[UID_STATE_DEAD_TASKS]);
Jin Qian67f252c2017-04-13 17:07:58 -0700305}
306
Jin Qian012f2002017-01-10 16:10:35 -0800307static int uid_io_show(struct seq_file *m, void *v)
308{
309 struct uid_entry *uid_entry;
310 unsigned long bkt;
311
Wei Wang7f1ad082017-03-13 12:22:21 -0700312 rt_mutex_lock(&uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -0800313
Jin Qian67f252c2017-04-13 17:07:58 -0700314 update_io_stats_all_locked();
Jin Qian012f2002017-01-10 16:10:35 -0800315
316 hash_for_each(hash_table, bkt, uid_entry, hash) {
Jin Qian62eb9f92017-03-02 13:39:43 -0800317 seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
Jin Qian012f2002017-01-10 16:10:35 -0800318 uid_entry->uid,
319 uid_entry->io[UID_STATE_FOREGROUND].rchar,
320 uid_entry->io[UID_STATE_FOREGROUND].wchar,
321 uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
322 uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
323 uid_entry->io[UID_STATE_BACKGROUND].rchar,
324 uid_entry->io[UID_STATE_BACKGROUND].wchar,
325 uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
Jin Qian62eb9f92017-03-02 13:39:43 -0800326 uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
327 uid_entry->io[UID_STATE_FOREGROUND].fsync,
328 uid_entry->io[UID_STATE_BACKGROUND].fsync);
Jin Qian012f2002017-01-10 16:10:35 -0800329 }
330
Wei Wang7f1ad082017-03-13 12:22:21 -0700331 rt_mutex_unlock(&uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -0800332
333 return 0;
334}
335
336static int uid_io_open(struct inode *inode, struct file *file)
337{
338 return single_open(file, uid_io_show, PDE_DATA(inode));
339}
340
341static const struct file_operations uid_io_fops = {
342 .open = uid_io_open,
343 .read = seq_read,
344 .llseek = seq_lseek,
345 .release = single_release,
346};
347
348static int uid_procstat_open(struct inode *inode, struct file *file)
349{
350 return single_open(file, NULL, NULL);
351}
352
353static ssize_t uid_procstat_write(struct file *file,
354 const char __user *buffer, size_t count, loff_t *ppos)
355{
356 struct uid_entry *uid_entry;
357 uid_t uid;
358 int argc, state;
359 char input[128];
360
361 if (count >= sizeof(input))
362 return -EINVAL;
363
364 if (copy_from_user(input, buffer, count))
365 return -EFAULT;
366
367 input[count] = '\0';
368
369 argc = sscanf(input, "%u %d", &uid, &state);
370 if (argc != 2)
371 return -EINVAL;
372
373 if (state != UID_STATE_BACKGROUND && state != UID_STATE_FOREGROUND)
374 return -EINVAL;
375
Wei Wang7f1ad082017-03-13 12:22:21 -0700376 rt_mutex_lock(&uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -0800377
378 uid_entry = find_or_register_uid(uid);
Jin Qian8782d8f2017-01-17 17:26:07 -0800379 if (!uid_entry) {
Wei Wang7f1ad082017-03-13 12:22:21 -0700380 rt_mutex_unlock(&uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -0800381 return -EINVAL;
382 }
383
Jin Qian8782d8f2017-01-17 17:26:07 -0800384 if (uid_entry->state == state) {
Wei Wang7f1ad082017-03-13 12:22:21 -0700385 rt_mutex_unlock(&uid_lock);
Jin Qian8782d8f2017-01-17 17:26:07 -0800386 return count;
387 }
388
Jin Qiancd5e19c2017-05-22 12:08:06 -0700389 update_io_stats_uid_locked(uid_entry);
Jin Qian012f2002017-01-10 16:10:35 -0800390
391 uid_entry->state = state;
392
Wei Wang7f1ad082017-03-13 12:22:21 -0700393 rt_mutex_unlock(&uid_lock);
Jin Qian012f2002017-01-10 16:10:35 -0800394
395 return count;
396}
397
398static const struct file_operations uid_procstat_fops = {
399 .open = uid_procstat_open,
400 .release = single_release,
401 .write = uid_procstat_write,
402};
403
jinqian69014222015-03-11 10:44:50 -0700404static int process_notifier(struct notifier_block *self,
405 unsigned long cmd, void *v)
406{
407 struct task_struct *task = v;
408 struct uid_entry *uid_entry;
409 cputime_t utime, stime;
410 uid_t uid;
411
412 if (!task)
413 return NOTIFY_OK;
414
Wei Wang7f1ad082017-03-13 12:22:21 -0700415 rt_mutex_lock(&uid_lock);
Amit Pundir48a99062015-04-15 00:40:21 +0530416 uid = from_kuid_munged(current_user_ns(), task_uid(task));
jinqian69014222015-03-11 10:44:50 -0700417 uid_entry = find_or_register_uid(uid);
418 if (!uid_entry) {
419 pr_err("%s: failed to find uid %d\n", __func__, uid);
420 goto exit;
421 }
422
423 task_cputime_adjusted(task, &utime, &stime);
424 uid_entry->utime += utime;
425 uid_entry->stime += stime;
426
Jin Qiancd5e19c2017-05-22 12:08:06 -0700427 add_uid_io_stats(uid_entry, task, UID_STATE_DEAD_TASKS);
Jin Qian012f2002017-01-10 16:10:35 -0800428
jinqian69014222015-03-11 10:44:50 -0700429exit:
Wei Wang7f1ad082017-03-13 12:22:21 -0700430 rt_mutex_unlock(&uid_lock);
jinqian69014222015-03-11 10:44:50 -0700431 return NOTIFY_OK;
432}
433
434static struct notifier_block process_notifier_block = {
435 .notifier_call = process_notifier,
436};
437
Jin Qian012f2002017-01-10 16:10:35 -0800438static int __init proc_uid_sys_stats_init(void)
jinqian69014222015-03-11 10:44:50 -0700439{
440 hash_init(hash_table);
441
Jin Qian012f2002017-01-10 16:10:35 -0800442 cpu_parent = proc_mkdir("uid_cputime", NULL);
443 if (!cpu_parent) {
444 pr_err("%s: failed to create uid_cputime proc entry\n",
445 __func__);
446 goto err;
jinqian69014222015-03-11 10:44:50 -0700447 }
448
Jin Qian012f2002017-01-10 16:10:35 -0800449 proc_create_data("remove_uid_range", 0222, cpu_parent,
450 &uid_remove_fops, NULL);
451 proc_create_data("show_uid_stat", 0444, cpu_parent,
452 &uid_cputime_fops, NULL);
jinqian69014222015-03-11 10:44:50 -0700453
Jin Qian012f2002017-01-10 16:10:35 -0800454 io_parent = proc_mkdir("uid_io", NULL);
455 if (!io_parent) {
456 pr_err("%s: failed to create uid_io proc entry\n",
457 __func__);
458 goto err;
459 }
460
461 proc_create_data("stats", 0444, io_parent,
462 &uid_io_fops, NULL);
463
464 proc_parent = proc_mkdir("uid_procstat", NULL);
465 if (!proc_parent) {
466 pr_err("%s: failed to create uid_procstat proc entry\n",
467 __func__);
468 goto err;
469 }
470
471 proc_create_data("set", 0222, proc_parent,
472 &uid_procstat_fops, NULL);
jinqian69014222015-03-11 10:44:50 -0700473
474 profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block);
475
476 return 0;
Jin Qian012f2002017-01-10 16:10:35 -0800477
478err:
479 remove_proc_subtree("uid_cputime", NULL);
480 remove_proc_subtree("uid_io", NULL);
481 remove_proc_subtree("uid_procstat", NULL);
482 return -ENOMEM;
jinqian69014222015-03-11 10:44:50 -0700483}
484
Jin Qian012f2002017-01-10 16:10:35 -0800485early_initcall(proc_uid_sys_stats_init);