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.

Merge tag 'eventfs-v6.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull eventfs updates from Steven Rostedt:

- Remove "lookup" parameter of create_dir_dentry() and
create_file_dentry(). These functions were called by lookup and the
readdir logic, where readdir needed it to up the ref count of the
dentry but the lookup did not. A "lookup" parameter was passed in to
tell it what to do, but this complicated the code. It is better to
just always up the ref count and require the caller to decrement it,
even for lookup.

- Modify the .iterate_shared callback to not use the dcache_readdir()
logic and just handle what gets displayed by that one function. This
removes the need for eventfs to hijack the file->private_data from
the dcache_readdir() "cursor" pointer, and makes the code a bit more
sane

- Use the root and instance inodes for default ownership. Instead of
walking the dentry tree and updating each dentry gid, use the
getattr(), setattr() and permission() callbacks to set the ownership
and permissions using the root or instance as the default

- Some other optimizations with the eventfs iterate_shared logic

- Hard-code the inodes for eventfs to the same number for files, and
the same number for directories

- Have getdent() not create dentries/inodes in iterate_shared() as now
it has hard-coded inode numbers

- Use kcalloc() instead of kzalloc() on a list of elements

- Fix seq_buf warning and make static work properly.

* tag 'eventfs-v6.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
seq_buf: Make DECLARE_SEQ_BUF() usable
eventfs: Use kcalloc() instead of kzalloc()
eventfs: Do not create dentries nor inodes in iterate_shared
eventfs: Have the inodes all for files and directories all be the same
eventfs: Shortcut eventfs_iterate() by skipping entries already read
eventfs: Read ei->entries before ei->children in eventfs_iterate()
eventfs: Do ctx->pos update for all iterations in eventfs_iterate()
eventfs: Have eventfs_iterate() stop immediately if ei->is_freed is set
tracefs/eventfs: Use root and instance inodes as default ownership
eventfs: Stop using dcache_readdir() for getdents()
eventfs: Remove "lookup" parameter from create_dir/file_dentry()

+288 -260
+174 -175
fs/tracefs/event_inode.c
··· 32 32 */ 33 33 static DEFINE_MUTEX(eventfs_mutex); 34 34 35 + /* Choose something "unique" ;-) */ 36 + #define EVENTFS_FILE_INODE_INO 0x12c4e37 37 + #define EVENTFS_DIR_INODE_INO 0x134b2f5 38 + 35 39 /* 36 40 * The eventfs_inode (ei) itself is protected by SRCU. It is released from 37 41 * its parent's list and will have is_freed set (under eventfs_mutex). ··· 49 45 EVENTFS_SAVE_MODE = BIT(16), 50 46 EVENTFS_SAVE_UID = BIT(17), 51 47 EVENTFS_SAVE_GID = BIT(18), 48 + EVENTFS_TOPLEVEL = BIT(19), 52 49 }; 53 50 54 51 #define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1) ··· 57 52 static struct dentry *eventfs_root_lookup(struct inode *dir, 58 53 struct dentry *dentry, 59 54 unsigned int flags); 60 - static int dcache_dir_open_wrapper(struct inode *inode, struct file *file); 61 - static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx); 62 - static int eventfs_release(struct inode *inode, struct file *file); 55 + static int eventfs_iterate(struct file *file, struct dir_context *ctx); 63 56 64 57 static void update_attr(struct eventfs_attr *attr, struct iattr *iattr) 65 58 { ··· 97 94 /* Preallocate the children mode array if necessary */ 98 95 if (!(dentry->d_inode->i_mode & S_IFDIR)) { 99 96 if (!ei->entry_attrs) { 100 - ei->entry_attrs = kzalloc(sizeof(*ei->entry_attrs) * ei->nr_entries, 97 + ei->entry_attrs = kcalloc(ei->nr_entries, sizeof(*ei->entry_attrs), 101 98 GFP_NOFS); 102 99 if (!ei->entry_attrs) { 103 100 ret = -ENOMEM; ··· 120 117 * The events directory dentry is never freed, unless its 121 118 * part of an instance that is deleted. It's attr is the 122 119 * default for its child files and directories. 123 - * Do not update it. It's not used for its own mode or ownership 120 + * Do not update it. It's not used for its own mode or ownership. 124 121 */ 125 - if (!ei->is_events) 122 + if (ei->is_events) { 123 + /* But it still needs to know if it was modified */ 124 + if (iattr->ia_valid & ATTR_UID) 125 + ei->attr.mode |= EVENTFS_SAVE_UID; 126 + if (iattr->ia_valid & ATTR_GID) 127 + ei->attr.mode |= EVENTFS_SAVE_GID; 128 + } else { 126 129 update_attr(&ei->attr, iattr); 130 + } 127 131 128 132 } else { 129 133 name = dentry->d_name.name; ··· 148 138 return ret; 149 139 } 150 140 141 + static void update_top_events_attr(struct eventfs_inode *ei, struct dentry *dentry) 142 + { 143 + struct inode *inode; 144 + 145 + /* Only update if the "events" was on the top level */ 146 + if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL)) 147 + return; 148 + 149 + /* Get the tracefs root inode. */ 150 + inode = d_inode(dentry->d_sb->s_root); 151 + ei->attr.uid = inode->i_uid; 152 + ei->attr.gid = inode->i_gid; 153 + } 154 + 155 + static void set_top_events_ownership(struct inode *inode) 156 + { 157 + struct tracefs_inode *ti = get_tracefs(inode); 158 + struct eventfs_inode *ei = ti->private; 159 + struct dentry *dentry; 160 + 161 + /* The top events directory doesn't get automatically updated */ 162 + if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL)) 163 + return; 164 + 165 + dentry = ei->dentry; 166 + 167 + update_top_events_attr(ei, dentry); 168 + 169 + if (!(ei->attr.mode & EVENTFS_SAVE_UID)) 170 + inode->i_uid = ei->attr.uid; 171 + 172 + if (!(ei->attr.mode & EVENTFS_SAVE_GID)) 173 + inode->i_gid = ei->attr.gid; 174 + } 175 + 176 + static int eventfs_get_attr(struct mnt_idmap *idmap, 177 + const struct path *path, struct kstat *stat, 178 + u32 request_mask, unsigned int flags) 179 + { 180 + struct dentry *dentry = path->dentry; 181 + struct inode *inode = d_backing_inode(dentry); 182 + 183 + set_top_events_ownership(inode); 184 + 185 + generic_fillattr(idmap, request_mask, inode, stat); 186 + return 0; 187 + } 188 + 189 + static int eventfs_permission(struct mnt_idmap *idmap, 190 + struct inode *inode, int mask) 191 + { 192 + set_top_events_ownership(inode); 193 + return generic_permission(idmap, inode, mask); 194 + } 195 + 151 196 static const struct inode_operations eventfs_root_dir_inode_operations = { 152 197 .lookup = eventfs_root_lookup, 153 198 .setattr = eventfs_set_attr, 199 + .getattr = eventfs_get_attr, 200 + .permission = eventfs_permission, 154 201 }; 155 202 156 203 static const struct inode_operations eventfs_file_inode_operations = { ··· 215 148 }; 216 149 217 150 static const struct file_operations eventfs_file_operations = { 218 - .open = dcache_dir_open_wrapper, 219 151 .read = generic_read_dir, 220 - .iterate_shared = dcache_readdir_wrapper, 152 + .iterate_shared = eventfs_iterate, 221 153 .llseek = generic_file_llseek, 222 - .release = eventfs_release, 223 154 }; 224 155 225 156 /* Return the evenfs_inode of the "events" directory */ ··· 242 177 dentry = ei->dentry; 243 178 } while (!ei->is_events); 244 179 mutex_unlock(&eventfs_mutex); 180 + 181 + update_top_events_attr(ei, dentry); 245 182 246 183 return ei; 247 184 } ··· 356 289 inode->i_fop = fop; 357 290 inode->i_private = data; 358 291 292 + /* All files will have the same inode number */ 293 + inode->i_ino = EVENTFS_FILE_INODE_INO; 294 + 359 295 ti = get_tracefs(inode); 360 296 ti->flags |= TRACEFS_EVENT_INODE; 361 297 d_instantiate(dentry, inode); ··· 394 324 395 325 inode->i_op = &eventfs_root_dir_inode_operations; 396 326 inode->i_fop = &eventfs_file_operations; 327 + 328 + /* All directories will have the same inode number */ 329 + inode->i_ino = EVENTFS_DIR_INODE_INO; 397 330 398 331 ti = get_tracefs(inode); 399 332 ti->flags |= TRACEFS_EVENT_INODE; ··· 463 390 * @mode: The mode of the file. 464 391 * @data: The data to use to set the inode of the file with on open() 465 392 * @fops: The fops of the file to be created. 466 - * @lookup: If called by the lookup routine, in which case, dput() the created dentry. 467 393 * 468 394 * Create a dentry for a file of an eventfs_inode @ei and place it into the 469 - * address located at @e_dentry. If the @e_dentry already has a dentry, then 470 - * just do a dget() on it and return. Otherwise create the dentry and attach it. 395 + * address located at @e_dentry. 471 396 */ 472 397 static struct dentry * 473 398 create_file_dentry(struct eventfs_inode *ei, int idx, 474 399 struct dentry *parent, const char *name, umode_t mode, void *data, 475 - const struct file_operations *fops, bool lookup) 400 + const struct file_operations *fops) 476 401 { 477 402 struct eventfs_attr *attr = NULL; 478 403 struct dentry **e_dentry = &ei->d_children[idx]; ··· 485 414 } 486 415 /* If the e_dentry already has a dentry, use it */ 487 416 if (*e_dentry) { 488 - /* lookup does not need to up the ref count */ 489 - if (!lookup) 490 - dget(*e_dentry); 417 + dget(*e_dentry); 491 418 mutex_unlock(&eventfs_mutex); 492 419 return *e_dentry; 493 420 } ··· 510 441 * way to being freed, don't return it. If e_dentry is NULL 511 442 * it means it was already freed. 512 443 */ 513 - if (ei->is_freed) 444 + if (ei->is_freed) { 514 445 dentry = NULL; 515 - else 446 + } else { 516 447 dentry = *e_dentry; 517 - /* The lookup does not need to up the dentry refcount */ 518 - if (dentry && !lookup) 519 448 dget(dentry); 449 + } 520 450 mutex_unlock(&eventfs_mutex); 521 451 return dentry; 522 452 } ··· 532 464 dentry = NULL; 533 465 } 534 466 mutex_unlock(&eventfs_mutex); 535 - 536 - if (lookup) 537 - dput(dentry); 538 467 539 468 return dentry; 540 469 } ··· 565 500 * @pei: The eventfs_inode parent of ei. 566 501 * @ei: The eventfs_inode to create the directory for 567 502 * @parent: The dentry of the parent of this directory 568 - * @lookup: True if this is called by the lookup code 569 503 * 570 504 * This creates and attaches a directory dentry to the eventfs_inode @ei. 571 505 */ 572 506 static struct dentry * 573 507 create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, 574 - struct dentry *parent, bool lookup) 508 + struct dentry *parent) 575 509 { 576 510 struct dentry *dentry = NULL; 577 511 ··· 582 518 return NULL; 583 519 } 584 520 if (ei->dentry) { 585 - /* If the dentry already has a dentry, use it */ 521 + /* If the eventfs_inode already has a dentry, use it */ 586 522 dentry = ei->dentry; 587 - /* lookup does not need to up the ref count */ 588 - if (!lookup) 589 - dget(dentry); 523 + dget(dentry); 590 524 mutex_unlock(&eventfs_mutex); 591 525 return dentry; 592 526 } ··· 604 542 * way to being freed. 605 543 */ 606 544 dentry = ei->dentry; 607 - if (dentry && !lookup) 545 + if (dentry) 608 546 dget(dentry); 609 547 mutex_unlock(&eventfs_mutex); 610 548 return dentry; ··· 623 561 dentry = NULL; 624 562 } 625 563 mutex_unlock(&eventfs_mutex); 626 - 627 - if (lookup) 628 - dput(dentry); 629 564 630 565 return dentry; 631 566 } ··· 648 589 struct eventfs_inode *ei; 649 590 struct dentry *ei_dentry = NULL; 650 591 struct dentry *ret = NULL; 592 + struct dentry *d; 651 593 const char *name = dentry->d_name.name; 652 - bool created = false; 653 594 umode_t mode; 654 595 void *data; 655 596 int idx; ··· 685 626 ret = simple_lookup(dir, dentry, flags); 686 627 if (IS_ERR(ret)) 687 628 goto out; 688 - create_dir_dentry(ei, ei_child, ei_dentry, true); 689 - created = true; 690 - break; 691 - } 692 - 693 - if (created) 629 + d = create_dir_dentry(ei, ei_child, ei_dentry); 630 + dput(d); 694 631 goto out; 632 + } 695 633 696 634 for (i = 0; i < ei->nr_entries; i++) { 697 635 entry = &ei->entries[i]; ··· 706 650 ret = simple_lookup(dir, dentry, flags); 707 651 if (IS_ERR(ret)) 708 652 goto out; 709 - create_file_dentry(ei, i, ei_dentry, name, mode, cdata, 710 - fops, true); 653 + d = create_file_dentry(ei, i, ei_dentry, name, mode, cdata, fops); 654 + dput(d); 711 655 break; 712 656 } 713 657 } ··· 716 660 return ret; 717 661 } 718 662 719 - struct dentry_list { 720 - void *cursor; 721 - struct dentry **dentries; 722 - }; 723 - 724 - /** 725 - * eventfs_release - called to release eventfs file/dir 726 - * @inode: inode to be released 727 - * @file: file to be released (not used) 663 + /* 664 + * Walk the children of a eventfs_inode to fill in getdents(). 728 665 */ 729 - static int eventfs_release(struct inode *inode, struct file *file) 730 - { 731 - struct tracefs_inode *ti; 732 - struct dentry_list *dlist = file->private_data; 733 - void *cursor; 734 - int i; 735 - 736 - ti = get_tracefs(inode); 737 - if (!(ti->flags & TRACEFS_EVENT_INODE)) 738 - return -EINVAL; 739 - 740 - if (WARN_ON_ONCE(!dlist)) 741 - return -EINVAL; 742 - 743 - for (i = 0; dlist->dentries && dlist->dentries[i]; i++) { 744 - dput(dlist->dentries[i]); 745 - } 746 - 747 - cursor = dlist->cursor; 748 - kfree(dlist->dentries); 749 - kfree(dlist); 750 - file->private_data = cursor; 751 - return dcache_dir_close(inode, file); 752 - } 753 - 754 - static int add_dentries(struct dentry ***dentries, struct dentry *d, int cnt) 755 - { 756 - struct dentry **tmp; 757 - 758 - tmp = krealloc(*dentries, sizeof(d) * (cnt + 2), GFP_NOFS); 759 - if (!tmp) 760 - return -1; 761 - tmp[cnt] = d; 762 - tmp[cnt + 1] = NULL; 763 - *dentries = tmp; 764 - return 0; 765 - } 766 - 767 - /** 768 - * dcache_dir_open_wrapper - eventfs open wrapper 769 - * @inode: not used 770 - * @file: dir to be opened (to create it's children) 771 - * 772 - * Used to dynamic create file/dir with-in @file, all the 773 - * file/dir will be created. If already created then references 774 - * will be increased 775 - */ 776 - static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) 666 + static int eventfs_iterate(struct file *file, struct dir_context *ctx) 777 667 { 778 668 const struct file_operations *fops; 669 + struct inode *f_inode = file_inode(file); 779 670 const struct eventfs_entry *entry; 780 671 struct eventfs_inode *ei_child; 781 672 struct tracefs_inode *ti; 782 673 struct eventfs_inode *ei; 783 - struct dentry_list *dlist; 784 - struct dentry **dentries = NULL; 785 - struct dentry *parent = file_dentry(file); 786 - struct dentry *d; 787 - struct inode *f_inode = file_inode(file); 788 - const char *name = parent->d_name.name; 674 + const char *name; 789 675 umode_t mode; 790 - void *data; 791 - int cnt = 0; 792 676 int idx; 793 - int ret; 794 - int i; 795 - int r; 677 + int ret = -EINVAL; 678 + int ino; 679 + int i, r, c; 680 + 681 + if (!dir_emit_dots(file, ctx)) 682 + return 0; 796 683 797 684 ti = get_tracefs(f_inode); 798 685 if (!(ti->flags & TRACEFS_EVENT_INODE)) 799 686 return -EINVAL; 800 687 801 - if (WARN_ON_ONCE(file->private_data)) 802 - return -EINVAL; 688 + c = ctx->pos - 2; 803 689 804 690 idx = srcu_read_lock(&eventfs_srcu); 805 691 806 692 mutex_lock(&eventfs_mutex); 807 693 ei = READ_ONCE(ti->private); 694 + if (ei && ei->is_freed) 695 + ei = NULL; 808 696 mutex_unlock(&eventfs_mutex); 809 697 810 - if (!ei) { 811 - srcu_read_unlock(&eventfs_srcu, idx); 812 - return -EINVAL; 813 - } 698 + if (!ei) 699 + goto out; 814 700 701 + /* 702 + * Need to create the dentries and inodes to have a consistent 703 + * inode number. 704 + */ 705 + ret = 0; 815 706 816 - data = ei->data; 707 + /* Start at 'c' to jump over already read entries */ 708 + for (i = c; i < ei->nr_entries; i++, ctx->pos++) { 709 + void *cdata = ei->data; 817 710 818 - dlist = kmalloc(sizeof(*dlist), GFP_KERNEL); 819 - if (!dlist) { 820 - srcu_read_unlock(&eventfs_srcu, idx); 821 - return -ENOMEM; 822 - } 823 - 824 - inode_lock(parent->d_inode); 825 - list_for_each_entry_srcu(ei_child, &ei->children, list, 826 - srcu_read_lock_held(&eventfs_srcu)) { 827 - d = create_dir_dentry(ei, ei_child, parent, false); 828 - if (d) { 829 - ret = add_dentries(&dentries, d, cnt); 830 - if (ret < 0) 831 - break; 832 - cnt++; 833 - } 834 - } 835 - 836 - for (i = 0; i < ei->nr_entries; i++) { 837 - void *cdata = data; 838 711 entry = &ei->entries[i]; 839 712 name = entry->name; 713 + 840 714 mutex_lock(&eventfs_mutex); 841 - /* If ei->is_freed, then the event itself may be too */ 842 - if (!ei->is_freed) 843 - r = entry->callback(name, &mode, &cdata, &fops); 844 - else 845 - r = -1; 715 + /* If ei->is_freed then just bail here, nothing more to do */ 716 + if (ei->is_freed) { 717 + mutex_unlock(&eventfs_mutex); 718 + goto out; 719 + } 720 + r = entry->callback(name, &mode, &cdata, &fops); 846 721 mutex_unlock(&eventfs_mutex); 847 722 if (r <= 0) 848 723 continue; 849 - d = create_file_dentry(ei, i, parent, name, mode, cdata, fops, false); 850 - if (d) { 851 - ret = add_dentries(&dentries, d, cnt); 852 - if (ret < 0) 853 - break; 854 - cnt++; 855 - } 724 + 725 + ino = EVENTFS_FILE_INODE_INO; 726 + 727 + if (!dir_emit(ctx, name, strlen(name), ino, DT_REG)) 728 + goto out; 856 729 } 857 - inode_unlock(parent->d_inode); 730 + 731 + /* Subtract the skipped entries above */ 732 + c -= min((unsigned int)c, (unsigned int)ei->nr_entries); 733 + 734 + list_for_each_entry_srcu(ei_child, &ei->children, list, 735 + srcu_read_lock_held(&eventfs_srcu)) { 736 + 737 + if (c > 0) { 738 + c--; 739 + continue; 740 + } 741 + 742 + ctx->pos++; 743 + 744 + if (ei_child->is_freed) 745 + continue; 746 + 747 + name = ei_child->name; 748 + 749 + ino = EVENTFS_DIR_INODE_INO; 750 + 751 + if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR)) 752 + goto out_dec; 753 + } 754 + ret = 1; 755 + out: 858 756 srcu_read_unlock(&eventfs_srcu, idx); 859 - ret = dcache_dir_open(inode, file); 860 757 861 - /* 862 - * dcache_dir_open() sets file->private_data to a dentry cursor. 863 - * Need to save that but also save all the dentries that were 864 - * opened by this function. 865 - */ 866 - dlist->cursor = file->private_data; 867 - dlist->dentries = dentries; 868 - file->private_data = dlist; 869 758 return ret; 870 - } 871 759 872 - /* 873 - * This just sets the file->private_data back to the cursor and back. 874 - */ 875 - static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx) 876 - { 877 - struct dentry_list *dlist = file->private_data; 878 - int ret; 879 - 880 - file->private_data = dlist->cursor; 881 - ret = dcache_readdir(file, ctx); 882 - dlist->cursor = file->private_data; 883 - file->private_data = dlist; 884 - return ret; 760 + out_dec: 761 + /* Incremented ctx->pos without adding something, reset it */ 762 + ctx->pos--; 763 + goto out; 885 764 } 886 765 887 766 /** ··· 874 883 } 875 884 876 885 if (size) { 877 - ei->d_children = kzalloc(sizeof(*ei->d_children) * size, GFP_KERNEL); 886 + ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL); 878 887 if (!ei->d_children) { 879 888 kfree_const(ei->name); 880 889 kfree(ei); ··· 941 950 goto fail; 942 951 943 952 if (size) { 944 - ei->d_children = kzalloc(sizeof(*ei->d_children) * size, GFP_KERNEL); 953 + ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL); 945 954 if (!ei->d_children) 946 955 goto fail; 947 956 } ··· 958 967 /* Save the ownership of this directory */ 959 968 uid = d_inode(dentry->d_parent)->i_uid; 960 969 gid = d_inode(dentry->d_parent)->i_gid; 970 + 971 + /* 972 + * If the events directory is of the top instance, then parent 973 + * is NULL. Set the attr.mode to reflect this and its permissions will 974 + * default to the tracefs root dentry. 975 + */ 976 + if (!parent) 977 + ei->attr.mode = EVENTFS_TOPLEVEL; 961 978 962 979 /* This is used as the default ownership of the files and directories */ 963 980 ei->attr.uid = uid;
+110 -83
fs/tracefs/inode.c
··· 91 91 struct inode *inode, struct dentry *dentry, 92 92 umode_t mode) 93 93 { 94 + struct tracefs_inode *ti; 94 95 char *name; 95 96 int ret; 96 97 97 98 name = get_dname(dentry); 98 99 if (!name) 99 100 return -ENOMEM; 101 + 102 + /* 103 + * This is a new directory that does not take the default of 104 + * the rootfs. It becomes the default permissions for all the 105 + * files and directories underneath it. 106 + */ 107 + ti = get_tracefs(inode); 108 + ti->flags |= TRACEFS_INSTANCE_INODE; 109 + ti->private = inode; 100 110 101 111 /* 102 112 * The mkdir call can call the generic functions that create ··· 151 141 return ret; 152 142 } 153 143 154 - static const struct inode_operations tracefs_dir_inode_operations = { 144 + static void set_tracefs_inode_owner(struct inode *inode) 145 + { 146 + struct tracefs_inode *ti = get_tracefs(inode); 147 + struct inode *root_inode = ti->private; 148 + 149 + /* 150 + * If this inode has never been referenced, then update 151 + * the permissions to the superblock. 152 + */ 153 + if (!(ti->flags & TRACEFS_UID_PERM_SET)) 154 + inode->i_uid = root_inode->i_uid; 155 + 156 + if (!(ti->flags & TRACEFS_GID_PERM_SET)) 157 + inode->i_gid = root_inode->i_gid; 158 + } 159 + 160 + static int tracefs_permission(struct mnt_idmap *idmap, 161 + struct inode *inode, int mask) 162 + { 163 + set_tracefs_inode_owner(inode); 164 + return generic_permission(idmap, inode, mask); 165 + } 166 + 167 + static int tracefs_getattr(struct mnt_idmap *idmap, 168 + const struct path *path, struct kstat *stat, 169 + u32 request_mask, unsigned int flags) 170 + { 171 + struct inode *inode = d_backing_inode(path->dentry); 172 + 173 + set_tracefs_inode_owner(inode); 174 + generic_fillattr(idmap, request_mask, inode, stat); 175 + return 0; 176 + } 177 + 178 + static int tracefs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 179 + struct iattr *attr) 180 + { 181 + unsigned int ia_valid = attr->ia_valid; 182 + struct inode *inode = d_inode(dentry); 183 + struct tracefs_inode *ti = get_tracefs(inode); 184 + 185 + if (ia_valid & ATTR_UID) 186 + ti->flags |= TRACEFS_UID_PERM_SET; 187 + 188 + if (ia_valid & ATTR_GID) 189 + ti->flags |= TRACEFS_GID_PERM_SET; 190 + 191 + return simple_setattr(idmap, dentry, attr); 192 + } 193 + 194 + static const struct inode_operations tracefs_instance_dir_inode_operations = { 155 195 .lookup = simple_lookup, 156 196 .mkdir = tracefs_syscall_mkdir, 157 197 .rmdir = tracefs_syscall_rmdir, 198 + .permission = tracefs_permission, 199 + .getattr = tracefs_getattr, 200 + .setattr = tracefs_setattr, 201 + }; 202 + 203 + static const struct inode_operations tracefs_dir_inode_operations = { 204 + .lookup = simple_lookup, 205 + .permission = tracefs_permission, 206 + .getattr = tracefs_getattr, 207 + .setattr = tracefs_setattr, 208 + }; 209 + 210 + static const struct inode_operations tracefs_file_inode_operations = { 211 + .permission = tracefs_permission, 212 + .getattr = tracefs_getattr, 213 + .setattr = tracefs_setattr, 158 214 }; 159 215 160 216 struct inode *tracefs_get_inode(struct super_block *sb) ··· 258 182 struct tracefs_fs_info { 259 183 struct tracefs_mount_opts mount_opts; 260 184 }; 261 - 262 - static void change_gid(struct dentry *dentry, kgid_t gid) 263 - { 264 - if (!dentry->d_inode) 265 - return; 266 - dentry->d_inode->i_gid = gid; 267 - } 268 - 269 - /* 270 - * Taken from d_walk, but without he need for handling renames. 271 - * Nothing can be renamed while walking the list, as tracefs 272 - * does not support renames. This is only called when mounting 273 - * or remounting the file system, to set all the files to 274 - * the given gid. 275 - */ 276 - static void set_gid(struct dentry *parent, kgid_t gid) 277 - { 278 - struct dentry *this_parent, *dentry; 279 - 280 - this_parent = parent; 281 - spin_lock(&this_parent->d_lock); 282 - 283 - change_gid(this_parent, gid); 284 - repeat: 285 - dentry = d_first_child(this_parent); 286 - resume: 287 - hlist_for_each_entry_from(dentry, d_sib) { 288 - struct tracefs_inode *ti; 289 - 290 - /* Note, getdents() can add a cursor dentry with no inode */ 291 - if (!dentry->d_inode) 292 - continue; 293 - 294 - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 295 - 296 - change_gid(dentry, gid); 297 - 298 - /* If this is the events directory, update that too */ 299 - ti = get_tracefs(dentry->d_inode); 300 - if (ti && (ti->flags & TRACEFS_EVENT_INODE)) 301 - eventfs_update_gid(dentry, gid); 302 - 303 - if (!hlist_empty(&dentry->d_children)) { 304 - spin_unlock(&this_parent->d_lock); 305 - spin_release(&dentry->d_lock.dep_map, _RET_IP_); 306 - this_parent = dentry; 307 - spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); 308 - goto repeat; 309 - } 310 - spin_unlock(&dentry->d_lock); 311 - } 312 - /* 313 - * All done at this level ... ascend and resume the search. 314 - */ 315 - rcu_read_lock(); 316 - ascend: 317 - if (this_parent != parent) { 318 - dentry = this_parent; 319 - this_parent = dentry->d_parent; 320 - 321 - spin_unlock(&dentry->d_lock); 322 - spin_lock(&this_parent->d_lock); 323 - 324 - /* go into the first sibling still alive */ 325 - hlist_for_each_entry_continue(dentry, d_sib) { 326 - if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) { 327 - rcu_read_unlock(); 328 - goto resume; 329 - } 330 - } 331 - goto ascend; 332 - } 333 - rcu_read_unlock(); 334 - spin_unlock(&this_parent->d_lock); 335 - return; 336 - } 337 185 338 186 static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts) 339 187 { ··· 331 331 if (!remount || opts->opts & BIT(Opt_uid)) 332 332 inode->i_uid = opts->uid; 333 333 334 - if (!remount || opts->opts & BIT(Opt_gid)) { 335 - /* Set all the group ids to the mount option */ 336 - set_gid(sb->s_root, opts->gid); 337 - } 334 + if (!remount || opts->opts & BIT(Opt_gid)) 335 + inode->i_gid = opts->gid; 338 336 339 337 return 0; 340 338 } ··· 566 568 return dentry; 567 569 } 568 570 571 + /* Find the inode that this will use for default */ 572 + static struct inode *instance_inode(struct dentry *parent, struct inode *inode) 573 + { 574 + struct tracefs_inode *ti; 575 + 576 + /* If parent is NULL then use root inode */ 577 + if (!parent) 578 + return d_inode(inode->i_sb->s_root); 579 + 580 + /* Find the inode that is flagged as an instance or the root inode */ 581 + while (!IS_ROOT(parent)) { 582 + ti = get_tracefs(d_inode(parent)); 583 + if (ti->flags & TRACEFS_INSTANCE_INODE) 584 + break; 585 + parent = parent->d_parent; 586 + } 587 + 588 + return d_inode(parent); 589 + } 590 + 569 591 /** 570 592 * tracefs_create_file - create a file in the tracefs filesystem 571 593 * @name: a pointer to a string containing the name of the file to create. ··· 616 598 struct dentry *parent, void *data, 617 599 const struct file_operations *fops) 618 600 { 601 + struct tracefs_inode *ti; 619 602 struct dentry *dentry; 620 603 struct inode *inode; 621 604 ··· 635 616 if (unlikely(!inode)) 636 617 return tracefs_failed_creating(dentry); 637 618 619 + ti = get_tracefs(inode); 620 + ti->private = instance_inode(parent, inode); 621 + 638 622 inode->i_mode = mode; 623 + inode->i_op = &tracefs_file_inode_operations; 639 624 inode->i_fop = fops ? fops : &tracefs_file_operations; 640 625 inode->i_private = data; 641 626 inode->i_uid = d_inode(dentry->d_parent)->i_uid; ··· 652 629 static struct dentry *__create_dir(const char *name, struct dentry *parent, 653 630 const struct inode_operations *ops) 654 631 { 632 + struct tracefs_inode *ti; 655 633 struct dentry *dentry = tracefs_start_creating(name, parent); 656 634 struct inode *inode; 657 635 ··· 669 645 inode->i_fop = &simple_dir_operations; 670 646 inode->i_uid = d_inode(dentry->d_parent)->i_uid; 671 647 inode->i_gid = d_inode(dentry->d_parent)->i_gid; 648 + 649 + ti = get_tracefs(inode); 650 + ti->private = instance_inode(parent, inode); 672 651 673 652 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 674 653 inc_nlink(inode); ··· 703 676 if (security_locked_down(LOCKDOWN_TRACEFS)) 704 677 return NULL; 705 678 706 - return __create_dir(name, parent, &simple_dir_inode_operations); 679 + return __create_dir(name, parent, &tracefs_dir_inode_operations); 707 680 } 708 681 709 682 /** ··· 734 707 if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir)) 735 708 return NULL; 736 709 737 - dentry = __create_dir(name, parent, &tracefs_dir_inode_operations); 710 + dentry = __create_dir(name, parent, &tracefs_instance_dir_inode_operations); 738 711 if (!dentry) 739 712 return NULL; 740 713
+3
fs/tracefs/internal.h
··· 5 5 enum { 6 6 TRACEFS_EVENT_INODE = BIT(1), 7 7 TRACEFS_EVENT_TOP_INODE = BIT(2), 8 + TRACEFS_GID_PERM_SET = BIT(3), 9 + TRACEFS_UID_PERM_SET = BIT(4), 10 + TRACEFS_INSTANCE_INODE = BIT(5), 8 11 }; 9 12 10 13 struct tracefs_inode {
+1 -2
include/linux/seq_buf.h
··· 22 22 }; 23 23 24 24 #define DECLARE_SEQ_BUF(NAME, SIZE) \ 25 - char __ ## NAME ## _buffer[SIZE] = ""; \ 26 25 struct seq_buf NAME = { \ 27 - .buffer = &__ ## NAME ## _buffer, \ 26 + .buffer = (char[SIZE]) { 0 }, \ 28 27 .size = SIZE, \ 29 28 } 30 29