Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.18-rc8 417 lines 12 kB view raw
1/* Global fscache object list maintainer and viewer 2 * 3 * Copyright (C) 2009 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 Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12#define FSCACHE_DEBUG_LEVEL COOKIE 13#include <linux/module.h> 14#include <linux/seq_file.h> 15#include <linux/slab.h> 16#include <linux/key.h> 17#include <keys/user-type.h> 18#include "internal.h" 19 20static struct rb_root fscache_object_list; 21static DEFINE_RWLOCK(fscache_object_list_lock); 22 23struct fscache_objlist_data { 24 unsigned long config; /* display configuration */ 25#define FSCACHE_OBJLIST_CONFIG_KEY 0x00000001 /* show object keys */ 26#define FSCACHE_OBJLIST_CONFIG_AUX 0x00000002 /* show object auxdata */ 27#define FSCACHE_OBJLIST_CONFIG_COOKIE 0x00000004 /* show objects with cookies */ 28#define FSCACHE_OBJLIST_CONFIG_NOCOOKIE 0x00000008 /* show objects without cookies */ 29#define FSCACHE_OBJLIST_CONFIG_BUSY 0x00000010 /* show busy objects */ 30#define FSCACHE_OBJLIST_CONFIG_IDLE 0x00000020 /* show idle objects */ 31#define FSCACHE_OBJLIST_CONFIG_PENDWR 0x00000040 /* show objects with pending writes */ 32#define FSCACHE_OBJLIST_CONFIG_NOPENDWR 0x00000080 /* show objects without pending writes */ 33#define FSCACHE_OBJLIST_CONFIG_READS 0x00000100 /* show objects with active reads */ 34#define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ 35#define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ 36#define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ 37#define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with work */ 38#define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without work */ 39}; 40 41/* 42 * Add an object to the object list 43 * - we use the address of the fscache_object structure as the key into the 44 * tree 45 */ 46void fscache_objlist_add(struct fscache_object *obj) 47{ 48 struct fscache_object *xobj; 49 struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; 50 51 ASSERT(RB_EMPTY_NODE(&obj->objlist_link)); 52 53 write_lock(&fscache_object_list_lock); 54 55 while (*p) { 56 parent = *p; 57 xobj = rb_entry(parent, struct fscache_object, objlist_link); 58 59 if (obj < xobj) 60 p = &(*p)->rb_left; 61 else if (obj > xobj) 62 p = &(*p)->rb_right; 63 else 64 BUG(); 65 } 66 67 rb_link_node(&obj->objlist_link, parent, p); 68 rb_insert_color(&obj->objlist_link, &fscache_object_list); 69 70 write_unlock(&fscache_object_list_lock); 71} 72 73/* 74 * Remove an object from the object list. 75 */ 76void fscache_objlist_remove(struct fscache_object *obj) 77{ 78 if (RB_EMPTY_NODE(&obj->objlist_link)) 79 return; 80 81 write_lock(&fscache_object_list_lock); 82 83 BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); 84 rb_erase(&obj->objlist_link, &fscache_object_list); 85 86 write_unlock(&fscache_object_list_lock); 87} 88 89/* 90 * find the object in the tree on or after the specified index 91 */ 92static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) 93{ 94 struct fscache_object *pobj, *obj = NULL, *minobj = NULL; 95 struct rb_node *p; 96 unsigned long pos; 97 98 if (*_pos >= (unsigned long) ERR_PTR(-ENOENT)) 99 return NULL; 100 pos = *_pos; 101 102 /* banners (can't represent line 0 by pos 0 as that would involve 103 * returning a NULL pointer) */ 104 if (pos == 0) 105 return (struct fscache_object *)(long)++(*_pos); 106 if (pos < 3) 107 return (struct fscache_object *)pos; 108 109 pobj = (struct fscache_object *)pos; 110 p = fscache_object_list.rb_node; 111 while (p) { 112 obj = rb_entry(p, struct fscache_object, objlist_link); 113 if (pobj < obj) { 114 if (!minobj || minobj > obj) 115 minobj = obj; 116 p = p->rb_left; 117 } else if (pobj > obj) { 118 p = p->rb_right; 119 } else { 120 minobj = obj; 121 break; 122 } 123 obj = NULL; 124 } 125 126 if (!minobj) 127 *_pos = (unsigned long) ERR_PTR(-ENOENT); 128 else if (minobj != obj) 129 *_pos = (unsigned long) minobj; 130 return minobj; 131} 132 133/* 134 * set up the iterator to start reading from the first line 135 */ 136static void *fscache_objlist_start(struct seq_file *m, loff_t *_pos) 137 __acquires(&fscache_object_list_lock) 138{ 139 read_lock(&fscache_object_list_lock); 140 return fscache_objlist_lookup(_pos); 141} 142 143/* 144 * move to the next line 145 */ 146static void *fscache_objlist_next(struct seq_file *m, void *v, loff_t *_pos) 147{ 148 (*_pos)++; 149 return fscache_objlist_lookup(_pos); 150} 151 152/* 153 * clean up after reading 154 */ 155static void fscache_objlist_stop(struct seq_file *m, void *v) 156 __releases(&fscache_object_list_lock) 157{ 158 read_unlock(&fscache_object_list_lock); 159} 160 161/* 162 * display an object 163 */ 164static int fscache_objlist_show(struct seq_file *m, void *v) 165{ 166 struct fscache_objlist_data *data = m->private; 167 struct fscache_object *obj = v; 168 struct fscache_cookie *cookie; 169 unsigned long config = data->config; 170 char _type[3], *type; 171 u8 *p; 172 173 if ((unsigned long) v == 1) { 174 seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" 175 " EM EV FL S" 176 " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); 177 if (config & (FSCACHE_OBJLIST_CONFIG_KEY | 178 FSCACHE_OBJLIST_CONFIG_AUX)) 179 seq_puts(m, " "); 180 if (config & FSCACHE_OBJLIST_CONFIG_KEY) 181 seq_puts(m, "OBJECT_KEY"); 182 if ((config & (FSCACHE_OBJLIST_CONFIG_KEY | 183 FSCACHE_OBJLIST_CONFIG_AUX)) == 184 (FSCACHE_OBJLIST_CONFIG_KEY | FSCACHE_OBJLIST_CONFIG_AUX)) 185 seq_puts(m, ", "); 186 if (config & FSCACHE_OBJLIST_CONFIG_AUX) 187 seq_puts(m, "AUX_DATA"); 188 seq_puts(m, "\n"); 189 return 0; 190 } 191 192 if ((unsigned long) v == 2) { 193 seq_puts(m, "======== ======== ==== ===== === === === == =====" 194 " == == == =" 195 " | ================ == == ================"); 196 if (config & (FSCACHE_OBJLIST_CONFIG_KEY | 197 FSCACHE_OBJLIST_CONFIG_AUX)) 198 seq_puts(m, " ================"); 199 seq_puts(m, "\n"); 200 return 0; 201 } 202 203 /* filter out any unwanted objects */ 204#define FILTER(criterion, _yes, _no) \ 205 do { \ 206 unsigned long yes = FSCACHE_OBJLIST_CONFIG_##_yes; \ 207 unsigned long no = FSCACHE_OBJLIST_CONFIG_##_no; \ 208 if (criterion) { \ 209 if (!(config & yes)) \ 210 return 0; \ 211 } else { \ 212 if (!(config & no)) \ 213 return 0; \ 214 } \ 215 } while(0) 216 217 cookie = obj->cookie; 218 if (~config) { 219 FILTER(cookie->def, 220 COOKIE, NOCOOKIE); 221 FILTER(fscache_object_is_active(obj) || 222 obj->n_ops != 0 || 223 obj->n_obj_ops != 0 || 224 obj->flags || 225 !list_empty(&obj->dependents), 226 BUSY, IDLE); 227 FILTER(test_bit(FSCACHE_OBJECT_PENDING_WRITE, &obj->flags), 228 PENDWR, NOPENDWR); 229 FILTER(atomic_read(&obj->n_reads), 230 READS, NOREADS); 231 FILTER(obj->events & obj->event_mask, 232 EVENTS, NOEVENTS); 233 FILTER(work_busy(&obj->work), WORK, NOWORK); 234 } 235 236 seq_printf(m, 237 "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %2lx %1x | ", 238 obj->debug_id, 239 obj->parent ? obj->parent->debug_id : -1, 240 obj->state->short_name, 241 obj->n_children, 242 obj->n_ops, 243 obj->n_obj_ops, 244 obj->n_in_progress, 245 obj->n_exclusive, 246 atomic_read(&obj->n_reads), 247 obj->event_mask, 248 obj->events, 249 obj->flags, 250 work_busy(&obj->work)); 251 252 if (fscache_use_cookie(obj)) { 253 uint16_t keylen = 0, auxlen = 0; 254 255 switch (cookie->type) { 256 case 0: 257 type = "IX"; 258 break; 259 case 1: 260 type = "DT"; 261 break; 262 default: 263 snprintf(_type, sizeof(_type), "%02u", 264 cookie->type); 265 type = _type; 266 break; 267 } 268 269 seq_printf(m, "%-16s %s %2lx %16p", 270 cookie->def->name, 271 type, 272 cookie->flags, 273 cookie->netfs_data); 274 275 if (config & FSCACHE_OBJLIST_CONFIG_KEY) 276 keylen = cookie->key_len; 277 278 if (config & FSCACHE_OBJLIST_CONFIG_AUX) 279 auxlen = cookie->aux_len; 280 281 if (keylen > 0 || auxlen > 0) { 282 seq_puts(m, " "); 283 p = keylen <= sizeof(cookie->inline_key) ? 284 cookie->inline_key : cookie->key; 285 for (; keylen > 0; keylen--) 286 seq_printf(m, "%02x", *p++); 287 if (auxlen > 0) { 288 if (config & FSCACHE_OBJLIST_CONFIG_KEY) 289 seq_puts(m, ", "); 290 p = auxlen <= sizeof(cookie->inline_aux) ? 291 cookie->inline_aux : cookie->aux; 292 for (; auxlen > 0; auxlen--) 293 seq_printf(m, "%02x", *p++); 294 } 295 } 296 297 seq_puts(m, "\n"); 298 fscache_unuse_cookie(obj); 299 } else { 300 seq_puts(m, "<no_netfs>\n"); 301 } 302 return 0; 303} 304 305static const struct seq_operations fscache_objlist_ops = { 306 .start = fscache_objlist_start, 307 .stop = fscache_objlist_stop, 308 .next = fscache_objlist_next, 309 .show = fscache_objlist_show, 310}; 311 312/* 313 * get the configuration for filtering the list 314 */ 315static void fscache_objlist_config(struct fscache_objlist_data *data) 316{ 317#ifdef CONFIG_KEYS 318 const struct user_key_payload *confkey; 319 unsigned long config; 320 struct key *key; 321 const char *buf; 322 int len; 323 324 key = request_key(&key_type_user, "fscache:objlist", NULL); 325 if (IS_ERR(key)) 326 goto no_config; 327 328 config = 0; 329 rcu_read_lock(); 330 331 confkey = user_key_payload_rcu(key); 332 if (!confkey) { 333 /* key was revoked */ 334 rcu_read_unlock(); 335 key_put(key); 336 goto no_config; 337 } 338 339 buf = confkey->data; 340 341 for (len = confkey->datalen - 1; len >= 0; len--) { 342 switch (buf[len]) { 343 case 'K': config |= FSCACHE_OBJLIST_CONFIG_KEY; break; 344 case 'A': config |= FSCACHE_OBJLIST_CONFIG_AUX; break; 345 case 'C': config |= FSCACHE_OBJLIST_CONFIG_COOKIE; break; 346 case 'c': config |= FSCACHE_OBJLIST_CONFIG_NOCOOKIE; break; 347 case 'B': config |= FSCACHE_OBJLIST_CONFIG_BUSY; break; 348 case 'b': config |= FSCACHE_OBJLIST_CONFIG_IDLE; break; 349 case 'W': config |= FSCACHE_OBJLIST_CONFIG_PENDWR; break; 350 case 'w': config |= FSCACHE_OBJLIST_CONFIG_NOPENDWR; break; 351 case 'R': config |= FSCACHE_OBJLIST_CONFIG_READS; break; 352 case 'r': config |= FSCACHE_OBJLIST_CONFIG_NOREADS; break; 353 case 'S': config |= FSCACHE_OBJLIST_CONFIG_WORK; break; 354 case 's': config |= FSCACHE_OBJLIST_CONFIG_NOWORK; break; 355 } 356 } 357 358 rcu_read_unlock(); 359 key_put(key); 360 361 if (!(config & (FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE))) 362 config |= FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE; 363 if (!(config & (FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE))) 364 config |= FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE; 365 if (!(config & (FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR))) 366 config |= FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR; 367 if (!(config & (FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS))) 368 config |= FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS; 369 if (!(config & (FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS))) 370 config |= FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS; 371 if (!(config & (FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK))) 372 config |= FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK; 373 374 data->config = config; 375 return; 376 377no_config: 378#endif 379 data->config = ULONG_MAX; 380} 381 382/* 383 * open "/proc/fs/fscache/objects" to provide a list of active objects 384 * - can be configured by a user-defined key added to the caller's keyrings 385 */ 386static int fscache_objlist_open(struct inode *inode, struct file *file) 387{ 388 struct fscache_objlist_data *data; 389 390 data = __seq_open_private(file, &fscache_objlist_ops, sizeof(*data)); 391 if (!data) 392 return -ENOMEM; 393 394 /* get the configuration key */ 395 fscache_objlist_config(data); 396 397 return 0; 398} 399 400/* 401 * clean up on close 402 */ 403static int fscache_objlist_release(struct inode *inode, struct file *file) 404{ 405 struct seq_file *m = file->private_data; 406 407 kfree(m->private); 408 m->private = NULL; 409 return seq_release(inode, file); 410} 411 412const struct file_operations fscache_objlist_fops = { 413 .open = fscache_objlist_open, 414 .read = seq_read, 415 .llseek = seq_lseek, 416 .release = fscache_objlist_release, 417};