• Jim Cromie's avatar
    dyndbg: add drm.debug style (drm/parameters/debug) bitmap support · b9400852
    Jim Cromie authored
    Add kernel_param_ops and callbacks to use a class-map to validate and
    apply input to a sysfs-node, which allows users to control classes
    defined in that class-map.  This supports uses like:
    
      echo 0x3 > /sys/module/drm/parameters/debug
    
    IE add these:
    
     - int param_set_dyndbg_classes()
     - int param_get_dyndbg_classes()
     - struct kernel_param_ops param_ops_dyndbg_classes
    
    Following the model of kernel/params.c STANDARD_PARAM_DEFS, these are
    non-static and exported.  This might be unnecessary here.
    
    get/set use an augmented kernel_param; the arg refs a new struct
    ddebug_class_param, which contains:
    
    - A ptr to user's state-store; a union of &ulong for drm.debug, &int
      for nouveau level debug.  By ref'g the client's bit-state _var, code
      coordinates with existing code (like drm_debug_enabled) which uses
      it, so existing/remaining calls can work unchanged.  Changing
      drm.debug to a ulong allows use of BIT() etc.
    
    - FLAGS: dyndbg.flags toggled by changes to bitmap. Usually just "p".
    
    - MAP: a pointer to struct ddebug_classes_map, which maps those
      class-names to .class_ids 0..N that the module is using.  This
      class-map is declared & initialized by DECLARE_DYNDBG_CLASSMAP.
    
    - map-type: 4 enums DD_CLASS_TYPE_* select 2 input forms and 2 meanings.
    
    numeric input:
      DD_CLASS_TYPE_DISJOINT_BITS	integer input, independent bits. ie: drm.debug
      DD_CLASS_TYPE_LEVEL_NUM	integer input, 0..N levels
    
    classnames-list (comma separated) input:
      DD_CLASS_TYPE_DISJOINT_NAMES	each name affects a bit, others preserved
      DD_CLASS_TYPE_LEVEL_NAMES	names have level meanings, like kern_levels.h
    
    _NAMES    - comma-separated classnames (with optional +-)
    _NUM      - numeric input, 0-N expected
    _BITS     - numeric input, 0x1F bitmap form expected
    
    _DISJOINT - bits are independent
    _LEVEL    - (x<y) on bit-pos.
    
    _DISJOINT treats input like a bit-vector (ala drm.debug), and sets
    each bit accordingly.  LEVEL is layered on top of this.
    
    _LEVEL treats input like a bit-pos:N, then sets bits(0..N)=1, and
    bits(N+1..max)=0.  This applies (bit<N) semantics on top of disjoint
    bits.
    
    USAGES:
    
    A potentially typical _DISJOINT_NAMES use:
    
      echo +DRM_UT_CORE,+DRM_UT_KMS,-DRM_UT_DRIVER,-DRM_UT_ATOMIC \
           > /sys/module/drm/parameters/debug_catnames
    
    A naive _LEVEL_NAMES use, with one class, that sets all in the
    class-map according to (x<y):
    
      : problem seen
      echo +L7 > /sys/module/test_dynamic_debug/parameters/p_level_names
      : problem solved
      echo -L1 > /sys/module/test_dynamic_debug/parameters/p_level_names
    
    Note this artifact:
    
      : this is same as prev cmd (due to +/-)
      echo L0 > /sys/module/test_dynamic_debug/parameters/p_level_names
    
      : this is "even-more" off, but same wo __pr_debug_class(L0, "..").
      echo -L0 > /sys/module/test_dynamic_debug/parameters/p_level_names
    
    A stress-test/make-work usage (kid toggling a light switch):
    
      echo +L7,L0,L7,L0,L7,L0,L7,L0,L7,L0,L7,L0,L7 \
           > /sys/module/test_dynamic_debug/parameters/p_level_names
    
    ddebug_apply_class_bitmap(): inside-fn, works on bitmaps, receives
    new-bits, finds diffs vs client-bitvector holding "current" state,
    and issues exec_query to commit the adjustment.
    
    param_set_dyndbg_classes(): interface fn, sends _NAMES to
    param_set_dyndbg_classnames() and returns, falls thru to handle _BITS,
    _NUM internally, and calls ddebug_apply_class_bitmap().  Finishes by
    updating state.
    
    param_set_dyndbg_classnames(): handles classnames-list in loop, calls
    ddebug_apply_class_bitmap for each, then updates state.
    
    NOTES:
    
    _LEVEL_ is overlay on _DISJOINT_; inputs are converted to a bitmask,
    by the callbacks.  IOW this is possible, and possibly confusing:
    
      echo class V3 +p > control
      echo class V1 -p > control
    
    IMO thats ok, relative verbosity is an interface property.
    
    _LEVEL_NUM maps still need class-names, even though the names are not
    usable at the sysfs interface (unlike with _NAMES style).  The names
    are the only way to >control the classes.
    
     - It must have a "V0" name,
       something below "V1" to turn "V1" off.
       __pr_debug_cls(V0,..) is printk, don't do that.
    
     - "class names" is required at the >control interface.
     - relative levels are not enforced at >control
    
    _LEVEL_NAMES bear +/- signs, which alters the on-bit-pos by 1.  IOW,
    +L2 means L0,L1,L2, and -L2 means just L0,L1.  This kinda spoils the
    readback fidelity, since the L0 bit gets turned on by any use of any
    L*, except "-L0".
    
    All the interface uncertainty here pertains to the _NAMES features.
    Nobody has actually asked for this, so its practical (if a little
    tedious) to split it out.
    Signed-off-by: default avatarJim Cromie <jim.cromie@gmail.com>
    Link: https://lore.kernel.org/r/20220904214134.408619-21-jim.cromie@gmail.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    b9400852
dynamic_debug.c 36.8 KB