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