| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* proc.c: proc files for key database enumeration | 
 | 2 |  * | 
 | 3 |  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 
 | 4 |  * Written by David Howells (dhowells@redhat.com) | 
 | 5 |  * | 
 | 6 |  * This program is free software; you can redistribute it and/or | 
 | 7 |  * modify it under the terms of the GNU General Public License | 
 | 8 |  * as published by the Free Software Foundation; either version | 
 | 9 |  * 2 of the License, or (at your option) any later version. | 
 | 10 |  */ | 
 | 11 |  | 
 | 12 | #include <linux/module.h> | 
 | 13 | #include <linux/init.h> | 
 | 14 | #include <linux/sched.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/fs.h> | 
 | 16 | #include <linux/proc_fs.h> | 
 | 17 | #include <linux/seq_file.h> | 
 | 18 | #include <asm/errno.h> | 
 | 19 | #include "internal.h" | 
 | 20 |  | 
 | 21 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 
 | 22 | static int proc_keys_open(struct inode *inode, struct file *file); | 
 | 23 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos); | 
 | 24 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); | 
 | 25 | static void proc_keys_stop(struct seq_file *p, void *v); | 
 | 26 | static int proc_keys_show(struct seq_file *m, void *v); | 
 | 27 |  | 
| Jan Engelhardt | 1996a10 | 2008-01-23 00:02:58 +0100 | [diff] [blame] | 28 | static const struct seq_operations proc_keys_ops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | 	.start	= proc_keys_start, | 
 | 30 | 	.next	= proc_keys_next, | 
 | 31 | 	.stop	= proc_keys_stop, | 
 | 32 | 	.show	= proc_keys_show, | 
 | 33 | }; | 
 | 34 |  | 
| Arjan van de Ven | 9c2e08c | 2007-02-12 00:55:37 -0800 | [diff] [blame] | 35 | static const struct file_operations proc_keys_fops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | 	.open		= proc_keys_open, | 
 | 37 | 	.read		= seq_read, | 
 | 38 | 	.llseek		= seq_lseek, | 
 | 39 | 	.release	= seq_release, | 
 | 40 | }; | 
 | 41 | #endif | 
 | 42 |  | 
 | 43 | static int proc_key_users_open(struct inode *inode, struct file *file); | 
 | 44 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); | 
 | 45 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); | 
 | 46 | static void proc_key_users_stop(struct seq_file *p, void *v); | 
 | 47 | static int proc_key_users_show(struct seq_file *m, void *v); | 
 | 48 |  | 
| Jan Engelhardt | 1996a10 | 2008-01-23 00:02:58 +0100 | [diff] [blame] | 49 | static const struct seq_operations proc_key_users_ops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 | 	.start	= proc_key_users_start, | 
 | 51 | 	.next	= proc_key_users_next, | 
 | 52 | 	.stop	= proc_key_users_stop, | 
 | 53 | 	.show	= proc_key_users_show, | 
 | 54 | }; | 
 | 55 |  | 
| Arjan van de Ven | 9c2e08c | 2007-02-12 00:55:37 -0800 | [diff] [blame] | 56 | static const struct file_operations proc_key_users_fops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 57 | 	.open		= proc_key_users_open, | 
 | 58 | 	.read		= seq_read, | 
 | 59 | 	.llseek		= seq_lseek, | 
 | 60 | 	.release	= seq_release, | 
 | 61 | }; | 
 | 62 |  | 
 | 63 | /*****************************************************************************/ | 
 | 64 | /* | 
 | 65 |  * declare the /proc files | 
 | 66 |  */ | 
 | 67 | static int __init key_proc_init(void) | 
 | 68 | { | 
 | 69 | 	struct proc_dir_entry *p; | 
 | 70 |  | 
 | 71 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 
| Alexey Dobriyan | da91d2e | 2008-04-29 01:01:27 -0700 | [diff] [blame] | 72 | 	p = proc_create("keys", 0, NULL, &proc_keys_fops); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | 	if (!p) | 
 | 74 | 		panic("Cannot create /proc/keys\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 75 | #endif | 
 | 76 |  | 
| Alexey Dobriyan | da91d2e | 2008-04-29 01:01:27 -0700 | [diff] [blame] | 77 | 	p = proc_create("key-users", 0, NULL, &proc_key_users_fops); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | 	if (!p) | 
 | 79 | 		panic("Cannot create /proc/key-users\n"); | 
 | 80 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | 	return 0; | 
 | 82 |  | 
 | 83 | } /* end key_proc_init() */ | 
 | 84 |  | 
 | 85 | __initcall(key_proc_init); | 
 | 86 |  | 
 | 87 | /*****************************************************************************/ | 
 | 88 | /* | 
 | 89 |  * implement "/proc/keys" to provides a list of the keys on the system | 
 | 90 |  */ | 
 | 91 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 
 | 92 |  | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 93 | static struct rb_node *key_serial_next(struct rb_node *n) | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 94 | { | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 95 | 	struct user_namespace *user_ns = current_user_ns(); | 
 | 96 |  | 
 | 97 | 	n = rb_next(n); | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 98 | 	while (n) { | 
 | 99 | 		struct key *key = rb_entry(n, struct key, serial_node); | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 100 | 		if (key->user->user_ns == user_ns) | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 101 | 			break; | 
 | 102 | 		n = rb_next(n); | 
 | 103 | 	} | 
 | 104 | 	return n; | 
 | 105 | } | 
 | 106 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | static int proc_keys_open(struct inode *inode, struct file *file) | 
 | 108 | { | 
 | 109 | 	return seq_open(file, &proc_keys_ops); | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 110 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 |  | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 112 | static struct key *find_ge_key(key_serial_t id) | 
 | 113 | { | 
 | 114 | 	struct user_namespace *user_ns = current_user_ns(); | 
 | 115 | 	struct rb_node *n = key_serial_tree.rb_node; | 
 | 116 | 	struct key *minkey = NULL; | 
 | 117 |  | 
 | 118 | 	while (n) { | 
 | 119 | 		struct key *key = rb_entry(n, struct key, serial_node); | 
 | 120 | 		if (id < key->serial) { | 
 | 121 | 			if (!minkey || minkey->serial > key->serial) | 
 | 122 | 				minkey = key; | 
 | 123 | 			n = n->rb_left; | 
 | 124 | 		} else if (id > key->serial) { | 
 | 125 | 			n = n->rb_right; | 
 | 126 | 		} else { | 
 | 127 | 			minkey = key; | 
 | 128 | 			break; | 
 | 129 | 		} | 
 | 130 | 		key = NULL; | 
 | 131 | 	} | 
 | 132 |  | 
 | 133 | 	if (!minkey) | 
 | 134 | 		return NULL; | 
 | 135 |  | 
 | 136 | 	for (;;) { | 
 | 137 | 		if (minkey->user->user_ns == user_ns) | 
 | 138 | 			return minkey; | 
 | 139 | 		n = rb_next(&minkey->serial_node); | 
 | 140 | 		if (!n) | 
 | 141 | 			return NULL; | 
 | 142 | 		minkey = rb_entry(n, struct key, serial_node); | 
 | 143 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 | } | 
 | 145 |  | 
 | 146 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos) | 
| James Morris | 86abcf9 | 2009-06-18 22:00:05 +1000 | [diff] [blame] | 147 | 	__acquires(key_serial_lock) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 148 | { | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 149 | 	key_serial_t pos = *_pos; | 
 | 150 | 	struct key *key; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 |  | 
 | 152 | 	spin_lock(&key_serial_lock); | 
 | 153 |  | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 154 | 	if (*_pos > INT_MAX) | 
 | 155 | 		return NULL; | 
 | 156 | 	key = find_ge_key(pos); | 
 | 157 | 	if (!key) | 
 | 158 | 		return NULL; | 
 | 159 | 	*_pos = key->serial; | 
 | 160 | 	return &key->serial_node; | 
 | 161 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 162 |  | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 163 | static inline key_serial_t key_node_serial(struct rb_node *n) | 
 | 164 | { | 
 | 165 | 	struct key *key = rb_entry(n, struct key, serial_node); | 
 | 166 | 	return key->serial; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | } | 
 | 168 |  | 
 | 169 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) | 
 | 170 | { | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 171 | 	struct rb_node *n; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 |  | 
| Serge E. Hallyn | ad73a71 | 2009-09-02 09:14:05 +0100 | [diff] [blame] | 173 | 	n = key_serial_next(v); | 
 | 174 | 	if (n) | 
 | 175 | 		*_pos = key_node_serial(n); | 
 | 176 | 	return n; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 177 | } | 
 | 178 |  | 
 | 179 | static void proc_keys_stop(struct seq_file *p, void *v) | 
| James Morris | 86abcf9 | 2009-06-18 22:00:05 +1000 | [diff] [blame] | 180 | 	__releases(key_serial_lock) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 181 | { | 
 | 182 | 	spin_unlock(&key_serial_lock); | 
 | 183 | } | 
 | 184 |  | 
 | 185 | static int proc_keys_show(struct seq_file *m, void *v) | 
 | 186 | { | 
| David Howells | 927942a | 2010-06-11 17:31:10 +0100 | [diff] [blame] | 187 | 	const struct cred *cred = current_cred(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 188 | 	struct rb_node *_p = v; | 
 | 189 | 	struct key *key = rb_entry(_p, struct key, serial_node); | 
 | 190 | 	struct timespec now; | 
 | 191 | 	unsigned long timo; | 
| David Howells | 927942a | 2010-06-11 17:31:10 +0100 | [diff] [blame] | 192 | 	key_ref_t key_ref, skey_ref; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 193 | 	char xbuf[12]; | 
| Michael LeMay | 06ec7be | 2006-06-26 00:24:56 -0700 | [diff] [blame] | 194 | 	int rc; | 
 | 195 |  | 
| David Howells | 927942a | 2010-06-11 17:31:10 +0100 | [diff] [blame] | 196 | 	key_ref = make_key_ref(key, 0); | 
 | 197 |  | 
 | 198 | 	/* determine if the key is possessed by this process (a test we can | 
 | 199 | 	 * skip if the key does not indicate the possessor can view it | 
 | 200 | 	 */ | 
 | 201 | 	if (key->perm & KEY_POS_VIEW) { | 
 | 202 | 		skey_ref = search_my_process_keyrings(key->type, key, | 
 | 203 | 						      lookup_user_key_possessed, | 
 | 204 | 						      cred); | 
 | 205 | 		if (!IS_ERR(skey_ref)) { | 
 | 206 | 			key_ref_put(skey_ref); | 
 | 207 | 			key_ref = make_key_ref(key, 1); | 
 | 208 | 		} | 
 | 209 | 	} | 
 | 210 |  | 
| Michael LeMay | 06ec7be | 2006-06-26 00:24:56 -0700 | [diff] [blame] | 211 | 	/* check whether the current task is allowed to view the key (assuming | 
| David Howells | d84f4f9 | 2008-11-14 10:39:23 +1100 | [diff] [blame] | 212 | 	 * non-possession) | 
 | 213 | 	 * - the caller holds a spinlock, and thus the RCU read lock, making our | 
 | 214 | 	 *   access to __current_cred() safe | 
 | 215 | 	 */ | 
| David Howells | 927942a | 2010-06-11 17:31:10 +0100 | [diff] [blame] | 216 | 	rc = key_task_permission(key_ref, cred, KEY_VIEW); | 
| Michael LeMay | 06ec7be | 2006-06-26 00:24:56 -0700 | [diff] [blame] | 217 | 	if (rc < 0) | 
 | 218 | 		return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 219 |  | 
 | 220 | 	now = current_kernel_time(); | 
 | 221 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 222 | 	rcu_read_lock(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 223 |  | 
 | 224 | 	/* come up with a suitable timeout value */ | 
 | 225 | 	if (key->expiry == 0) { | 
 | 226 | 		memcpy(xbuf, "perm", 5); | 
| David Howells | 7b1b916 | 2009-09-02 09:14:11 +0100 | [diff] [blame] | 227 | 	} else if (now.tv_sec >= key->expiry) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 228 | 		memcpy(xbuf, "expd", 5); | 
| David Howells | 7b1b916 | 2009-09-02 09:14:11 +0100 | [diff] [blame] | 229 | 	} else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 230 | 		timo = key->expiry - now.tv_sec; | 
 | 231 |  | 
 | 232 | 		if (timo < 60) | 
 | 233 | 			sprintf(xbuf, "%lus", timo); | 
 | 234 | 		else if (timo < 60*60) | 
 | 235 | 			sprintf(xbuf, "%lum", timo / 60); | 
 | 236 | 		else if (timo < 60*60*24) | 
 | 237 | 			sprintf(xbuf, "%luh", timo / (60*60)); | 
 | 238 | 		else if (timo < 60*60*24*7) | 
 | 239 | 			sprintf(xbuf, "%lud", timo / (60*60*24)); | 
 | 240 | 		else | 
 | 241 | 			sprintf(xbuf, "%luw", timo / (60*60*24*7)); | 
 | 242 | 	} | 
 | 243 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 244 | #define showflag(KEY, LETTER, FLAG) \ | 
 | 245 | 	(test_bit(FLAG,	&(KEY)->flags) ? LETTER : '-') | 
 | 246 |  | 
| David Howells | 664cceb | 2005-09-28 17:03:15 +0100 | [diff] [blame] | 247 | 	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 | 		   key->serial, | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 249 | 		   showflag(key, 'I', KEY_FLAG_INSTANTIATED), | 
 | 250 | 		   showflag(key, 'R', KEY_FLAG_REVOKED), | 
 | 251 | 		   showflag(key, 'D', KEY_FLAG_DEAD), | 
 | 252 | 		   showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | 
 | 253 | 		   showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 
 | 254 | 		   showflag(key, 'N', KEY_FLAG_NEGATIVE), | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 | 		   atomic_read(&key->usage), | 
 | 256 | 		   xbuf, | 
 | 257 | 		   key->perm, | 
 | 258 | 		   key->uid, | 
 | 259 | 		   key->gid, | 
 | 260 | 		   key->type->name); | 
 | 261 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 262 | #undef showflag | 
 | 263 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | 	if (key->type->describe) | 
 | 265 | 		key->type->describe(key, m); | 
 | 266 | 	seq_putc(m, '\n'); | 
 | 267 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 268 | 	rcu_read_unlock(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 | 	return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 | } | 
 | 271 |  | 
 | 272 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ | 
 | 273 |  | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 274 | static struct rb_node *__key_user_next(struct rb_node *n) | 
 | 275 | { | 
 | 276 | 	while (n) { | 
 | 277 | 		struct key_user *user = rb_entry(n, struct key_user, node); | 
 | 278 | 		if (user->user_ns == current_user_ns()) | 
 | 279 | 			break; | 
 | 280 | 		n = rb_next(n); | 
 | 281 | 	} | 
 | 282 | 	return n; | 
 | 283 | } | 
 | 284 |  | 
 | 285 | static struct rb_node *key_user_next(struct rb_node *n) | 
 | 286 | { | 
 | 287 | 	return __key_user_next(rb_next(n)); | 
 | 288 | } | 
 | 289 |  | 
 | 290 | static struct rb_node *key_user_first(struct rb_root *r) | 
 | 291 | { | 
 | 292 | 	struct rb_node *n = rb_first(r); | 
 | 293 | 	return __key_user_next(n); | 
 | 294 | } | 
| David Howells | 7b1b916 | 2009-09-02 09:14:11 +0100 | [diff] [blame] | 295 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | /*****************************************************************************/ | 
 | 297 | /* | 
 | 298 |  * implement "/proc/key-users" to provides a list of the key users | 
 | 299 |  */ | 
 | 300 | static int proc_key_users_open(struct inode *inode, struct file *file) | 
 | 301 | { | 
 | 302 | 	return seq_open(file, &proc_key_users_ops); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | } | 
 | 304 |  | 
 | 305 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | 
| James Morris | 86abcf9 | 2009-06-18 22:00:05 +1000 | [diff] [blame] | 306 | 	__acquires(key_user_lock) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 307 | { | 
 | 308 | 	struct rb_node *_p; | 
 | 309 | 	loff_t pos = *_pos; | 
 | 310 |  | 
 | 311 | 	spin_lock(&key_user_lock); | 
 | 312 |  | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 313 | 	_p = key_user_first(&key_user_tree); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 314 | 	while (pos > 0 && _p) { | 
 | 315 | 		pos--; | 
| Serge E. Hallyn | 454804a | 2009-02-26 18:28:04 -0600 | [diff] [blame] | 316 | 		_p = key_user_next(_p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | 	} | 
 | 318 |  | 
 | 319 | 	return _p; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | } | 
 | 321 |  | 
 | 322 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) | 
 | 323 | { | 
 | 324 | 	(*_pos)++; | 
| Justin P. Mattock | c5b60b5 | 2010-04-21 00:02:11 -0700 | [diff] [blame] | 325 | 	return key_user_next((struct rb_node *)v); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 326 | } | 
 | 327 |  | 
 | 328 | static void proc_key_users_stop(struct seq_file *p, void *v) | 
| James Morris | 86abcf9 | 2009-06-18 22:00:05 +1000 | [diff] [blame] | 329 | 	__releases(key_user_lock) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 330 | { | 
 | 331 | 	spin_unlock(&key_user_lock); | 
 | 332 | } | 
 | 333 |  | 
 | 334 | static int proc_key_users_show(struct seq_file *m, void *v) | 
 | 335 | { | 
 | 336 | 	struct rb_node *_p = v; | 
 | 337 | 	struct key_user *user = rb_entry(_p, struct key_user, node); | 
| David Howells | 0b77f5b | 2008-04-29 01:01:32 -0700 | [diff] [blame] | 338 | 	unsigned maxkeys = (user->uid == 0) ? | 
 | 339 | 		key_quota_root_maxkeys : key_quota_maxkeys; | 
 | 340 | 	unsigned maxbytes = (user->uid == 0) ? | 
 | 341 | 		key_quota_root_maxbytes : key_quota_maxbytes; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 342 |  | 
 | 343 | 	seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", | 
 | 344 | 		   user->uid, | 
 | 345 | 		   atomic_read(&user->usage), | 
 | 346 | 		   atomic_read(&user->nkeys), | 
 | 347 | 		   atomic_read(&user->nikeys), | 
 | 348 | 		   user->qnkeys, | 
| David Howells | 0b77f5b | 2008-04-29 01:01:32 -0700 | [diff] [blame] | 349 | 		   maxkeys, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 | 		   user->qnbytes, | 
| David Howells | 0b77f5b | 2008-04-29 01:01:32 -0700 | [diff] [blame] | 351 | 		   maxbytes); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 352 |  | 
 | 353 | 	return 0; | 
 | 354 |  | 
 | 355 | } |