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

Merge branch 'for-3.10-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

Pull cgroup fixes from Tejun Heo:

- Fix for yet another xattr bug which may lead to NULL deref.

- A subtle bug in for_each_descendant_pre(). This bug requires quite
specific conditions to trigger and isn't too likely to actually
happen in the wild, but maybe that just makes it that much more
nastier.

- A warning message added for silly cgroup re-mount (not -o remount,
but unmount followed by mount) behavior.

* 'for-3.10-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
cgroup: warn about mismatching options of a new mount of an existing hierarchy
cgroup: fix a subtle bug in descendant pre-order walk
cgroup: initialize xattr before calling d_instantiate()

+17 -16
+1 -1
include/linux/cgroup.h
··· 707 707 * 708 708 * If a subsystem synchronizes against the parent in its ->css_online() and 709 709 * before starting iterating, and synchronizes against @pos on each 710 - * iteration, any descendant cgroup which finished ->css_offline() is 710 + * iteration, any descendant cgroup which finished ->css_online() is 711 711 * guaranteed to be visible in the future iterations. 712 712 * 713 713 * In other words, the following guarantees that a descendant can't escape
+16 -15
kernel/cgroup.c
··· 1686 1686 */ 1687 1687 cgroup_drop_root(opts.new_root); 1688 1688 1689 - if (((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) && 1690 - root->flags != opts.flags) { 1691 - pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n"); 1692 - ret = -EINVAL; 1693 - goto drop_new_super; 1689 + if (root->flags != opts.flags) { 1690 + if ((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) { 1691 + pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n"); 1692 + ret = -EINVAL; 1693 + goto drop_new_super; 1694 + } else { 1695 + pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n"); 1696 + } 1694 1697 } 1695 1698 1696 1699 /* no subsys rebinding, so refcounts don't change */ ··· 2702 2699 goto out; 2703 2700 } 2704 2701 2702 + cfe->type = (void *)cft; 2703 + cfe->dentry = dentry; 2704 + dentry->d_fsdata = cfe; 2705 + simple_xattrs_init(&cfe->xattrs); 2706 + 2705 2707 mode = cgroup_file_mode(cft); 2706 2708 error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb); 2707 2709 if (!error) { 2708 - cfe->type = (void *)cft; 2709 - cfe->dentry = dentry; 2710 - dentry->d_fsdata = cfe; 2711 - simple_xattrs_init(&cfe->xattrs); 2712 2710 list_add_tail(&cfe->node, &parent->files); 2713 2711 cfe = NULL; 2714 2712 } ··· 2957 2953 WARN_ON_ONCE(!rcu_read_lock_held()); 2958 2954 2959 2955 /* if first iteration, pretend we just visited @cgroup */ 2960 - if (!pos) { 2961 - if (list_empty(&cgroup->children)) 2962 - return NULL; 2956 + if (!pos) 2963 2957 pos = cgroup; 2964 - } 2965 2958 2966 2959 /* visit the first child if exists */ 2967 2960 next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling); ··· 2966 2965 return next; 2967 2966 2968 2967 /* no child, visit my or the closest ancestor's next sibling */ 2969 - do { 2968 + while (pos != cgroup) { 2970 2969 next = list_entry_rcu(pos->sibling.next, struct cgroup, 2971 2970 sibling); 2972 2971 if (&next->sibling != &pos->parent->children) 2973 2972 return next; 2974 2973 2975 2974 pos = pos->parent; 2976 - } while (pos != cgroup); 2975 + } 2977 2976 2978 2977 return NULL; 2979 2978 }