用户空间辅助程序---热插拔

来源:互联网 发布:用ipad开淘宝店铺教程 编辑:程序博客网 时间:2024/06/05 09:10

原文地址:http://blog.chinaunix.net/uid-20786208-id-4158792.html

对于热插拔,当然网上有很多资料,包括刚开始我也简单的讲过usb 热插拔. 当时说道2.6以后的内核都用uevent机制来代替老的机制.(具体从那个版本改变的可以看linux官网开发记录)

由于在看《深入理解linux网络内幕》中网络设备初始化一节中又提到了,而看《深入linux设备驱动程序内核机制》中详细讲解.当然这里我也自己分析了一把^^,我们就接着usb热插拔事件继续说事: 当有usb插板事件的时候,会触发到drivers/usb/core/hub.c 中  
/* Handle physical or logical connection change events.
 * This routine is called when:
 * a port connection-change occurs;
 * a port enable-change occurs (often caused by EMI);
 * usb_reset_and_verify_device() encounters changed descriptors (as from
 * a firmware download)
 * caller already locked the hub
 */
static void hub_port_connect_change(struct usb_hub *hub, int port1,
u16 portstatus, u16 portchange)
{

...
/* Run it through the hoops (find a driver, etc) */
if (!status) {
status = usb_new_device(udev);
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}

...
}
这里我们只是做一个简单回忆 ,重点是 usb_new_device函数:

点击(此处)折叠或打开

  1. /**
  2.  * usb_new_device - perform initial device setup (usbcore-internal)
  3.  * @udev: newly addressed device (in ADDRESS state)
  4.  *
  5.  * This is called with devices which have been detected but not fully
  6.  * enumerated. The device descriptor is available, but not descriptors
  7.  * for any device configuration. The caller must have locked either
  8.  * the parent hub (if udev is a normal device) or else the
  9.  * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
  10.  * udev has already been installed, but udev is not yet visible through
  11.  * sysfs or other filesystem code.
  12.  *
  13.  * It will return if the device is configured properly or not. Zero if
  14.  * the interface was registered with the driver core; else a negative
  15.  * errno value.
  16.  *
  17.  * This call is synchronous, and may not be used in an interrupt context.
  18.  *
  19.  * Only the hub driver or root-hub registrar should ever call this.
  20.  */
  21. int usb_new_device(struct usb_device *udev)
  22. {
  23.     int err;

  24.     if (udev->parent) {
  25.         /* Increment the parent's count of unsuspended children */
  26.         usb_autoresume_device(udev->parent);

  27.         /* Initialize non-root-hub device wakeup to disabled;
  28.          * device (un)configuration controls wakeup capable
  29.          * sysfs power/wakeup controls wakeup enabled/disabled
  30.          */
  31.         device_init_wakeup(&udev->dev, 0);
  32.     }

  33.     err = usb_enumerate_device(udev);    /* Read descriptors */
  34.     if (err < 0)
  35.         goto fail;
  36.     dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
  37.             udev->devnum, udev->bus->busnum,
  38.             (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
  39.     /* export the usbdev device-node for libusb */
  40.     udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
  41.             (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

  42.     /* Tell the */
  43.     announce_device(udev);

  44.     if (udev->serial)
  45.         add_device_randomness(udev->serial, strlen(udev->serial));
  46.     if (udev->product)
  47.         add_device_randomness(udev->product, strlen(udev->product));
  48.     if (udev->manufacturer)
  49.         add_device_randomness(udev->manufacturer,
  50.                  strlen(udev->manufacturer));

  51.     /* Register the device. The device driver is responsible
  52.      * for configuring the device and invoking the add-device
  53.      * notifier chain (used by usbfs and possibly others).
  54.      */
  55.     err = device_add(&udev->dev);
  56.     if (err) {
  57.         dev_err(&udev->dev, "can't device_add, error %d\n", err);
  58.         goto fail;
  59.     }

  60.     (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
  61.     return err;

  62. fail:
  63.     usb_set_device_state(udev, USB_STATE_NOTATTACHED);
  64.     usb_stop_pm(udev);
  65.     return err;
  66. }

里面的具体的一些初始化这里不在一一说明,我们只看device_add函数:

点击(此处)折叠或打开

  1. /**
  2.  * device_add - add device to device hierarchy.
  3.  * @dev: device.
  4.  *
  5.  * This is part 2 of device_register(), though may be called
  6.  * separately _iff_ device_initialize() has been called separately.
  7.  *
  8.  * This adds @dev to the kobject hierarchy via kobject_add(), adds it
  9.  * to the global and sibling lists for the device, then
  10.  * adds it to the other relevant subsystems of the driver model.
  11.  *
  12.  * NOTE: _Never_ directly free @dev after calling this function, even
  13.  * if it returned an Always use put_device() to give up your
  14.  * reference instead.
  15.  */
  16. int device_add(struct device *dev)
  17. {
  18.     struct device *parent = NULL;
  19.     struct class_interface *class_intf;
  20.     int error = -EINVAL;

  21.     dev = get_device(dev);
  22.     if (!dev)
  23.         goto done;

  24.     if (!dev->p) {
  25.         error = device_private_init(dev);
  26.         if (error)
  27.             goto done;
  28.     }

  29.     /*
  30.      * for statically allocated devices, which should all be converted
  31.      * some day, we need to initialize the name. We prevent reading back
  32.      * the name, and force the use of dev_name()
  33.      */
  34.     if (dev->init_name) {
  35.         dev_set_name(dev, "%s", dev->init_name);
  36.         dev->init_name = NULL;
  37.     }

  38.     if (!dev_name(dev))
  39.         goto name_error;

  40.     pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

  41.     parent = get_device(dev->parent);
  42.     setup_parent(dev, parent);

  43.     /* use parent numa_node */
  44.     if (parent)
  45.         set_dev_node(dev, dev_to_node(parent));

  46.     /* first, register with generic layer. */
  47.     /* we require the name to be set before, and pass NULL */
  48.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
  49.     if (error)
  50.         goto Error;

  51.     /* notify platform of device entry */
  52.     if (platform_notify)
  53.         platform_notify(dev);

  54.     error = device_create_file(dev, &uevent_attr);
  55.     if (error)
  56.         goto attrError;

  57.     if (MAJOR(dev->devt)) {
  58.         error = device_create_file(dev, &devt_attr);
  59.         if (error)
  60.             goto ueventattrError;

  61.         error = device_create_sys_dev_entry(dev);
  62.         if (error)
  63.             goto devtattrError;

  64.         devtmpfs_create_node(dev);
  65.     }

  66.     error = device_add_class_symlinks(dev);
  67.     if (error)
  68.         goto SymlinkError;
  69.     error = device_add_attrs(dev);
  70.     if (error)
  71.         goto AttrsError;
  72.     error = bus_add_device(dev);
  73.     if (error)
  74.         goto BusError;
  75.     error = dpm_sysfs_add(dev);
  76.     if (error)
  77.         goto DPMError;
  78.     device_pm_add(dev);

  79.     /* Notify clients of device addition. This call must come
  80.      * after dpm_sysf_add() and before kobject_uevent().
  81.      */
  82.     if (dev->bus)
  83.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  84.                      BUS_NOTIFY_ADD_DEVICE, dev);

  85.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  86.     bus_probe_device(dev);
  87.     if (parent)
  88.         klist_add_tail(&dev->p->knode_parent,
  89.              &parent->p->klist_children);

  90.     if (dev->class) {
  91.         mutex_lock(&dev->class->p->class_mutex);
  92.         /* tie the class to the device */
  93.         klist_add_tail(&dev->knode_class,
  94.              &dev->class->p->class_devices);

  95.         /* notify any interfaces that the device is here */
  96.         list_for_each_entry(class_intf,
  97.                  &dev->class->p->class_interfaces, node)
  98.             if (class_intf->add_dev)
  99.                 class_intf->add_dev(dev, class_intf);
  100.         mutex_unlock(&dev->class->p->class_mutex);
  101.     }
  102. done:
  103.     put_device(dev);
  104.     return error;
  105.  DPMError:
  106.     bus_remove_device(dev);
  107.  BusError:
  108.     device_remove_attrs(dev);
  109.  AttrsError:
  110.     device_remove_class_symlinks(dev);
  111.  SymlinkError:
  112.     if (MAJOR(dev->devt))
  113.         device_remove_sys_dev_entry(dev);
  114.  devtattrError:
  115.     if (MAJOR(dev->devt))
  116.         device_remove_file(dev, &devt_attr);
  117.  ueventattrError:
  118.     device_remove_file(dev, &uevent_attr);
  119.  attrError:
  120.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  121.     kobject_del(&dev->kobj);
  122.  Error:
  123.     cleanup_device_parent(dev);
  124.     if (parent)
  125.         put_device(parent);
  126. name_error:
  127.     kfree(dev->p);
  128.     dev->= NULL;
  129.     goto done;
  130. }

这个函数除了对设备模型做了些工作,还通知了一些事件. kobject_uevent(&dev->kobj, KOBJ_ADD);忘了说上边的代码已经到了drivers/base/core.c中. 我们看到KOBJ_ADD操作。而具体支持的操作看头文件include/linux/kobject.h
/*
 * The actions here must match the index to the string array
 * in lib/kobject_uevent.c
 *
 * Do not add new actions here without checking with the driver-core
 * maintainers. Action strings are not meant to express subsystem
 * or device specific properties. In most cases you want to send a
 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
 * specific variables added to the event environment.
 */
enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};
那么kobject_uevent做了什么工作呢,我们知道,新内核机制已经变成uevent模式.
lib/kobject_uevent.c 

点击(此处)折叠或打开

  1. /**
  2.  * kobject_uevent - notify userspace by ending an uevent
  3.  *
  4.  * @action: action that is happening
  5.  * @kobj: struct kobject that the action is happening to
  6.  *
  7.  * Returns 0 if kobject_uevent() is completed with success or the
  8.  * corresponding error when it fails.
  9.  */
  10. int kobject_uevent(struct kobject *kobj, enum kobject_action action)
  11. {
  12.     return kobject_uevent_env(kobj, action, NULL);
  13. }
  14. EXPORT_SYMBOL_GPL(kobject_uevent);

好吧,调用了 kobject_uevent_env函数.

点击(此处)折叠或打开

  1. /**
  2.  * kobject_uevent_env - send an uevent with environmental data
  3.  *
  4.  * @action: action that is happening
  5.  * @kobj: struct kobject that the action is happening to
  6.  * @envp_ext: pointer to environmental data
  7.  *
  8.  * Returns 0 if kobject_uevent() is completed with success or the
  9.  * corresponding error when it fails.
  10.  */
  11. int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
  12.          char *envp_ext[])
  13. {
  14.     struct kobj_uevent_env *env;
  15.     const char *action_string = kobject_actions[action];
  16.     const char *devpath = NULL;
  17.     const char *subsystem;
  18.     struct kobject *top_kobj;
  19.     struct kset *kset;
  20.     struct kset_uevent_ops *uevent_ops;
  21.     u64 seq;
  22.     int i = 0;
  23.     int retval = 0;

  24.     pr_debug("kobject: '%s' (%p): %s\n",
  25.          kobject_name(kobj), kobj, __func__);

  26.     /* search the kset we belong to */
  27.     top_kobj = kobj;
  28.     while (!top_kobj->kset && top_kobj->parent)
  29.         top_kobj = top_kobj->parent;

  30.     if (!top_kobj->kset) {
  31.         pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  32.              "without kset!\n", kobject_name(kobj), kobj,
  33.              __func__);
  34.         return -EINVAL;
  35.     }

  36.     kset = top_kobj->kset;
  37.     uevent_ops = kset->uevent_ops;

  38.     /* skip the event, if uevent_suppress is set*/
  39.     if (kobj->uevent_suppress) {
  40.         pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  41.                  "caused the event to drop!\n",
  42.                  kobject_name(kobj), kobj, __func__);
  43.         return 0;
  44.     }
  45.     /* skip the event, if the filter returns zero. */
  46.     if (uevent_ops && uevent_ops->filter)
  47.         if (!uevent_ops->filter(kset, kobj)) {
  48.             pr_debug("kobject: '%s' (%p): %s: filter function "
  49.                  "caused the event to drop!\n",
  50.                  kobject_name(kobj), kobj, __func__);
  51.             return 0;
  52.         }

  53.     /* originating subsystem */
  54.     if (uevent_ops && uevent_ops->name)
  55.         subsystem = uevent_ops->name(kset, kobj);
  56.     else
  57.         subsystem = kobject_name(&kset->kobj);
  58.     if (!subsystem) {
  59.         pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  60.              "event to drop!\n", kobject_name(kobj), kobj,
  61.              __func__);
  62.         return 0;
  63.     }

  64.     /* environment buffer */
  65.     env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  66.     if (!env)
  67.         return -ENOMEM;

  68.     /* complete object path */
  69.     devpath = kobject_get_path(kobj, GFP_KERNEL);
  70.     if (!devpath) {
  71.         retval = -ENOENT;
  72.         goto exit;
  73.     }

  74.     /* default keys */
  75.     retval = add_uevent_var(env, "ACTION=%s", action_string);
  76.     if (retval)
  77.         goto exit;
  78.     retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  79.     if (retval)
  80.         goto exit;
  81.     retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  82.     if (retval)
  83.         goto exit;

  84.     /* keys passed in from the caller */
  85.     if (envp_ext) {
  86.         for (= 0; envp_ext[i]; i++) {
  87.             retval = add_uevent_var(env, "%s", envp_ext[i]);
  88.             if (retval)
  89.                 goto exit;
  90.         }
  91.     }

  92.     /* let the kset specific function add its stuff */
  93.     if (uevent_ops && uevent_ops->uevent) {
  94.         retval = uevent_ops->uevent(kset, kobj, env);
  95.         if (retval) {
  96.             pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  97.                  "%d\n", kobject_name(kobj), kobj,
  98.                  __func__, retval);
  99.             goto exit;
  100.         }
  101.     }

  102.     /*
  103.      * Mark "add" and "remove" events in the object to ensure proper
  104.      * events to userspace during automatic cleanup. If the object did
  105.      * send an "add" event, "remove" will automatically generated by
  106.      * the core, if not already done by the caller.
  107.      */
  108.     if (action == KOBJ_ADD)
  109.         kobj->state_add_uevent_sent = 1;
  110.     else if (action == KOBJ_REMOVE)
  111.         kobj->state_remove_uevent_sent = 1;

  112.     /* we will send an event, so request a new sequence number */
  113.     spin_lock(&sequence_lock);
  114.     seq = ++uevent_seqnum;
  115.     spin_unlock(&sequence_lock);
  116.     retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
  117.     if (retval)
  118.         goto exit;

  119. #if defined(CONFIG_NET)
  120.     /* send netlink message */
  121.     if (uevent_sock) {
  122.         struct sk_buff *skb;
  123.         size_t len;

  124.         /* allocate message with the maximum possible size */
  125.         len = strlen(action_string) + strlen(devpath) + 2;
  126.         skb = alloc_skb(len + env->buflen, GFP_KERNEL);
  127.         if (skb) {
  128.             char *scratch;

  129.             /* add header */
  130.             scratch = skb_put(skb, len);
  131.             sprintf(scratch, "%s@%s", action_string, devpath);

  132.             /* copy keys to our continuous event payload buffer */
  133.             for (= 0; i < env->envp_idx; i++) {
  134.                 len = strlen(env->envp[i]) + 1;
  135.                 scratch = skb_put(skb, len);
  136.                 strcpy(scratch, env->envp[i]);
  137.             }

  138.             NETLINK_CB(skb).dst_group = 1;
  139.             retval = netlink_broadcast(uevent_sock, skb, 0, 1,
  140.                          GFP_KERNEL);
  141.             /* ENOBUFS should be handled in userspace */
  142.             if (retval == -ENOBUFS || retval == -ESRCH)
  143.                 retval = 0;
  144.         } else
  145.             retval = -ENOMEM;
  146.     }
  147. #endif

  148.     /* call uevent_helper, usually only enabled during early boot */
  149.     if (uevent_helper[0]) {
  150.         char *argv [3];

  151.         argv [0] = uevent_helper;
  152.         argv [1] = (char *)subsystem;
  153.         argv [2] = NULL;
  154.         retval = add_uevent_var(env, "HOME=/");
  155.         if (retval)
  156.             goto exit;
  157.         retval = add_uevent_var(env,
  158.                     "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  159.         if (retval)
  160.             goto exit;

  161.         retval = call_usermodehelper(argv[0], argv,
  162.                      env->envp, UMH_WAIT_EXEC);
  163.     }

  164. exit:
  165.     kfree(devpath);
  166.     kfree(env);
  167.     return retval;
  168. }

这个函数里做了最重要的工作. 第一发送一个netlink组播;第二调用了call_usermodehelper执行用户空间的应用程序.
这里面不得不说uevent_helper变量.由它指定具体调用哪个应用程序.add_uevent_var只是传递一些变量.
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;  //系统默认的值
而CONFIG_UEVENT_HELPER_PATH,可以查看arch/XXX/configs/  里。一般是/sbin/XXX  。
当然从用户空间也可以修改这个值:
#cat  /proc/sys/kernel/hotplug 
or
#cat /sys/kernel/uevent_helper
可以查看当前系统设定的值,由于我做的是嵌入式系统,默认是/sbin/mdev (这里说明一下mdev只是udev缩减版,具体资料可以查一查就明白,它会检测设备模型下面一些变量值的变化并作出相应动作)
而对于为什么这两个变量的值是一样的,我做了简单分析:
第一个是procfs,我们看kernel/sysctl.c :
kernel_table :

点击(此处)折叠或打开

  1. static struct ctl_table kern_table[] = {
  2.     {
  3.         .ctl_name    = CTL_UNNUMBERED,
  4.         .procname    = "sched_child_runs_first",
  5.         .data        = &sysctl_sched_child_runs_first,
  6.         .maxlen        = sizeof(unsigned int),
  7.         .mode        = 0644,
  8.         .proc_handler    = &proc_dointvec,
  9.     },
  10. #ifdef CONFIG_SCHED_DEBUG
  11.     {
  12.         .ctl_name    = CTL_UNNUMBERED,
  13.         .procname    = "sched_min_granularity_ns",
  14.         .data        = &sysctl_sched_min_granularity,
  15.         .maxlen        = sizeof(unsigned int),
  16.         .mode        = 0644,
  17.         .proc_handler    = &sched_nr_latency_handler,
  18.         .strategy    = &sysctl_intvec,
  19.         .extra1        = &min_sched_granularity_ns,
  20.         .extra2        = &max_sched_granularity_ns,
  21.     },
  22.     {
  23.         .ctl_name    = CTL_UNNUMBERED,
  24.         .procname    = "sched_latency_ns",
  25.         .data        = &sysctl_sched_latency,
  26.         .maxlen        = sizeof(unsigned int),
  27.         .mode        = 0644,
  28.         .proc_handler    = &sched_nr_latency_handler,
  29.         .strategy    = &sysctl_intvec,
  30.         .extra1        = &min_sched_granularity_ns,
  31.         .extra2        = &max_sched_granularity_ns,
  32.     },
  33.     {
  34.         .ctl_name    = CTL_UNNUMBERED,
  35.         .procname    = "sched_wakeup_granularity_ns",
  36.         .data        = &sysctl_sched_wakeup_granularity,
  37.         .maxlen        = sizeof(unsigned int),
  38.         .mode        = 0644,
  39.         .proc_handler    = &proc_dointvec_minmax,
  40.         .strategy    = &sysctl_intvec,
  41.         .extra1        = &min_wakeup_granularity_ns,
  42.         .extra2        = &max_wakeup_granularity_ns,
  43.     },
  44.     {
  45.         .ctl_name    = CTL_UNNUMBERED,
  46.         .procname    = "sched_shares_ratelimit",
  47.         .data        = &sysctl_sched_shares_ratelimit,
  48.         .maxlen        = sizeof(unsigned int),
  49.         .mode        = 0644,
  50.         .proc_handler    = &proc_dointvec,
  51.     },
  52.     {
  53.         .ctl_name    = CTL_UNNUMBERED,
  54.         .procname    = "sched_shares_thresh",
  55.         .data        = &sysctl_sched_shares_thresh,
  56.         .maxlen        = sizeof(unsigned int),
  57.         .mode        = 0644,
  58.         .proc_handler    = &proc_dointvec_minmax,
  59.         .strategy    = &sysctl_intvec,
  60.         .extra1        = &zero,
  61.     },
  62.     {
  63.         .ctl_name    = CTL_UNNUMBERED,
  64.         .procname    = "sched_features",
  65.         .data        = &sysctl_sched_features,
  66.         .maxlen        = sizeof(unsigned int),
  67.         .mode        = 0644,
  68.         .proc_handler    = &proc_dointvec,
  69.     },
  70.     {
  71.         .ctl_name    = CTL_UNNUMBERED,
  72.         .procname    = "sched_migration_cost",
  73.         .data        = &sysctl_sched_migration_cost,
  74.         .maxlen        = sizeof(unsigned int),
  75.         .mode        = 0644,
  76.         .proc_handler    = &proc_dointvec,
  77.     },
  78.     {
  79.         .ctl_name    = CTL_UNNUMBERED,
  80.         .procname    = "sched_nr_migrate",
  81.         .data        = &sysctl_sched_nr_migrate,
  82.         .maxlen        = sizeof(unsigned int),
  83.         .mode        = 0644,
  84.         .proc_handler    = &proc_dointvec,
  85.     },
  86.     {
  87.         .ctl_name    = CTL_UNNUMBERED,
  88.         .procname    = "sched_time_avg",
  89.         .data        = &sysctl_sched_time_avg,
  90.         .maxlen        = sizeof(unsigned int),
  91.         .mode        = 0644,
  92.         .proc_handler    = &proc_dointvec,
  93.     },
  94.     {
  95.         .ctl_name    = CTL_UNNUMBERED,
  96.         .procname    = "timer_migration",
  97.         .data        = &sysctl_timer_migration,
  98.         .maxlen        = sizeof(unsigned int),
  99.         .mode        = 0644,
  100.         .proc_handler    = &proc_dointvec_minmax,
  101.         .strategy    = &sysctl_intvec,
  102.         .extra1        = &zero,
  103.         .extra2        = &one,
  104.     },
  105. #endif
  106.     {
  107.         .ctl_name    = CTL_UNNUMBERED,
  108.         .procname    = "sched_rt_period_us",
  109.         .data        = &sysctl_sched_rt_period,
  110.         .maxlen        = sizeof(unsigned int),
  111.         .mode        = 0644,
  112.         .proc_handler    = &sched_rt_handler,
  113.     },
  114.     {
  115.         .ctl_name    = CTL_UNNUMBERED,
  116.         .procname    = "sched_rt_runtime_us",
  117.         .data        = &sysctl_sched_rt_runtime,
  118.         .maxlen        = sizeof(int),
  119.         .mode        = 0644,
  120.         .proc_handler    = &sched_rt_handler,
  121.     },
  122.     {
  123.         .ctl_name    = CTL_UNNUMBERED,
  124.         .procname    = "sched_compat_yield",
  125.         .data        = &sysctl_sched_compat_yield,
  126.         .maxlen        = sizeof(unsigned int),
  127.         .mode        = 0644,
  128.         .proc_handler    = &proc_dointvec,
  129.     },
  130. #ifdef CONFIG_PROVE_LOCKING
  131.     {
  132.         .ctl_name    = CTL_UNNUMBERED,
  133.         .procname    = "prove_locking",
  134.         .data        = &prove_locking,
  135.         .maxlen        = sizeof(int),
  136.         .mode        = 0644,
  137.         .proc_handler    = &proc_dointvec,
  138.     },
  139. #endif
  140. #ifdef CONFIG_LOCK_STAT
  141.     {
  142.         .ctl_name    = CTL_UNNUMBERED,
  143.         .procname    = "lock_stat",
  144.         .data        = &lock_stat,
  145.         .maxlen        = sizeof(int),
  146.         .mode        = 0644,
  147.         .proc_handler    = &proc_dointvec,
  148.     },
  149. #endif
  150.     {
  151.         .ctl_name    = KERN_PANIC,
  152.         .procname    = "panic",
  153.         .data        = &panic_timeout,
  154.         .maxlen        = sizeof(int),
  155.         .mode        = 0644,
  156.         .proc_handler    = &proc_dointvec,
  157.     },
  158.     {
  159.         .ctl_name    = KERN_CORE_USES_PID,
  160.         .procname    = "core_uses_pid",
  161.         .data        = &core_uses_pid,
  162.         .maxlen        = sizeof(int),
  163.         .mode        = 0644,
  164.         .proc_handler    = &proc_dointvec,
  165.     },
  166.     {
  167.         .ctl_name    = KERN_CORE_PATTERN,
  168.         .procname    = "core_pattern",
  169.         .data        = core_pattern,
  170.         .maxlen        = CORENAME_MAX_SIZE,
  171.         .mode        = 0644,
  172.         .proc_handler    = &proc_dostring,
  173.         .strategy    = &sysctl_string,
  174.     },
  175.     {
  176.         .ctl_name    = CTL_UNNUMBERED,
  177.         .procname    = "core_pipe_limit",
  178.         .data        = &core_pipe_limit,
  179.         .maxlen        = sizeof(unsigned int),
  180.         .mode        = 0644,
  181.         .proc_handler    = &proc_dointvec,
  182.     },
  183. #ifdef CONFIG_PROC_SYSCTL
  184.     {
  185.         .procname    = "tainted",
  186.         .maxlen     = sizeof(long),
  187.         .mode        = 0644,
  188.         .proc_handler    = &proc_taint,
  189.     },
  190. #endif
  191. #ifdef CONFIG_LATENCYTOP
  192.     {
  193.         .procname    = "latencytop",
  194.         .data        = &latencytop_enabled,
  195.         .maxlen        = sizeof(int),
  196.         .mode        = 0644,
  197.         .proc_handler    = &proc_dointvec,
  198.     },
  199. #endif
  200. #ifdef CONFIG_BLK_DEV_INITRD
  201.     {
  202.         .ctl_name    = KERN_REALROOTDEV,
  203.         .procname    = "real-root-dev",
  204.         .data        = &real_root_dev,
  205.         .maxlen        = sizeof(int),
  206.         .mode        = 0644,
  207.         .proc_handler    = &proc_dointvec,
  208.     },
  209. #endif
  210.     {
  211.         .ctl_name    = CTL_UNNUMBERED,
  212.         .procname    = "print-fatal-signals",
  213.         .data        = &print_fatal_signals,
  214.         .maxlen        = sizeof(int),
  215.         .mode        = 0644,
  216.         .proc_handler    = &proc_dointvec,
  217.     },
  218. #ifdef CONFIG_SPARC
  219.     {
  220.         .ctl_name    = KERN_SPARC_REBOOT,
  221.         .procname    = "reboot-cmd",
  222.         .data        = reboot_command,
  223.         .maxlen        = 256,
  224.         .mode        = 0644,
  225.         .proc_handler    = &proc_dostring,
  226.         .strategy    = &sysctl_string,
  227.     },
  228.     {
  229.         .ctl_name    = KERN_SPARC_STOP_A,
  230.         .procname    = "stop-a",
  231.         .data        = &stop_a_enabled,
  232.         .maxlen        = sizeof (int),
  233.         .mode        = 0644,
  234.         .proc_handler    = &proc_dointvec,
  235.     },
  236.     {
  237.         .ctl_name    = KERN_SPARC_SCONS_PWROFF,
  238.         .procname    = "scons-poweroff",
  239.         .data        = &scons_pwroff,
  240.         .maxlen        = sizeof (int),
  241.         .mode        = 0644,
  242.         .proc_handler    = &proc_dointvec,
  243.     },
  244. #endif
  245. #ifdef CONFIG_SPARC64
  246.     {
  247.         .ctl_name    = CTL_UNNUMBERED,
  248.         .procname    = "tsb-ratio",
  249.         .data        = &sysctl_tsb_ratio,
  250.         .maxlen        = sizeof (int),
  251.         .mode        = 0644,
  252.         .proc_handler    = &proc_dointvec,
  253.     },
  254. #endif
  255. #ifdef __hppa__
  256.     {
  257.         .ctl_name    = KERN_HPPA_PWRSW,
  258.         .procname    = "soft-power",
  259.         .data        = &pwrsw_enabled,
  260.         .maxlen        = sizeof (int),
  261.          .mode        = 0644,
  262.         .proc_handler    = &proc_dointvec,
  263.     },
  264.     {
  265.         .ctl_name    = KERN_HPPA_UNALIGNED,
  266.         .procname    = "unaligned-trap",
  267.         .data        = &unaligned_enabled,
  268.         .maxlen        = sizeof (int),
  269.         .mode        = 0644,
  270.         .proc_handler    = &proc_dointvec,
  271.     },
  272. #endif
  273.     {
  274.         .ctl_name    = KERN_CTLALTDEL,
  275.         .procname    = "ctrl-alt-del",
  276.         .data        = &C_A_D,
  277.         .maxlen        = sizeof(int),
  278.         .mode        = 0644,
  279.         .proc_handler    = &proc_dointvec,
  280.     },
  281. #ifdef CONFIG_FUNCTION_TRACER
  282.     {
  283.         .ctl_name    = CTL_UNNUMBERED,
  284.         .procname    = "ftrace_enabled",
  285.         .data        = &ftrace_enabled,
  286.         .maxlen        = sizeof(int),
  287.         .mode        = 0644,
  288.         .proc_handler    = &ftrace_enable_sysctl,
  289.     },
  290. #endif
  291. #ifdef CONFIG_STACK_TRACER
  292.     {
  293.         .ctl_name    = CTL_UNNUMBERED,
  294.         .procname    = "stack_tracer_enabled",
  295.         .data        = &stack_tracer_enabled,
  296.         .maxlen        = sizeof(int),
  297.         .mode        = 0644,
  298.         .proc_handler    = &stack_trace_sysctl,
  299.     },
  300. #endif
  301. #ifdef CONFIG_TRACING
  302.     {
  303.         .ctl_name    = CTL_UNNUMBERED,
  304.         .procname    = "ftrace_dump_on_oops",
  305.         .data        = &ftrace_dump_on_oops,
  306.         .maxlen        = sizeof(int),
  307.         .mode        = 0644,
  308.         .proc_handler    = &proc_dointvec,
  309.     },
  310. #endif
  311. #ifdef CONFIG_MODULES
  312.     {
  313.         .ctl_name    = KERN_MODPROBE,
  314.         .procname    = "modprobe",
  315.         .data        = &modprobe_path,
  316.         .maxlen        = KMOD_PATH_LEN,
  317.         .mode        = 0644,
  318.         .proc_handler    = &proc_dostring,
  319.         .strategy    = &sysctl_string,
  320.     },
  321.     {
  322.         .ctl_name    = CTL_UNNUMBERED,
  323.         .procname    = "modules_disabled",
  324.         .data        = &modules_disabled,
  325.         .maxlen        = sizeof(int),
  326.         .mode        = 0644,
  327.         /* only handle a transition from default "0" to "1" */
  328.         .proc_handler    = &proc_dointvec_minmax,
  329.         .extra1        = &one,
  330.         .extra2        = &one,
  331.     },
  332. #endif
  333. #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
  334.     {
  335.         .ctl_name    = KERN_HOTPLUG,
  336.         .procname    = "hotplug",
  337.         .data        = &uevent_helper,
  338.         .maxlen        = UEVENT_HELPER_PATH_LEN,
  339.         .mode        = 0644,
  340.         .proc_handler    = &proc_dostring,
  341.         .strategy    = &sysctl_string,
  342.     },
  343. #endif
  344. #ifdef CONFIG_CHR_DEV_SG
  345.     {
  346.         .ctl_name    = KERN_SG_BIG_BUFF,
  347.         .procname    = "sg-big-buff",
  348.         .data        = &sg_big_buff,
  349.         .maxlen        = sizeof (int),
  350.         .mode        = 0444,
  351.         .proc_handler    = &proc_dointvec,
  352.     },
  353. #endif
  354. #ifdef CONFIG_BSD_PROCESS_ACCT
  355.     {
  356.         .ctl_name    = KERN_ACCT,
  357.         .procname    = "acct",
  358.         .data        = &acct_parm,
  359.         .maxlen        = 3*sizeof(int),
  360.         .mode        = 0644,
  361.         .proc_handler    = &proc_dointvec,
  362.     },
  363. #endif
  364. #ifdef CONFIG_MAGIC_SYSRQ
  365.     {
  366.         .ctl_name    = KERN_SYSRQ,
  367.         .procname    = "sysrq",
  368.         .data        = &__sysrq_enabled,
  369.         .maxlen        = sizeof (int),
  370.         .mode        = 0644,
  371.         .proc_handler    = &proc_dointvec,
  372.     },
  373. #endif
  374. #ifdef CONFIG_PROC_SYSCTL
  375.     {
  376.         .procname    = "cad_pid",
  377.         .data        = NULL,
  378.         .maxlen        = sizeof (int),
  379.         .mode        = 0600,
  380.         .proc_handler    = &proc_do_cad_pid,
  381.     },
  382. #endif
  383.     {
  384.         .ctl_name    = KERN_MAX_THREADS,
  385.         .procname    = "threads-max",
  386.         .data        = &max_threads,
  387.         .maxlen        = sizeof(int),
  388.         .mode        = 0644,
  389.         .proc_handler    = &proc_dointvec,
  390.     },
  391.     {
  392.         .ctl_name    = KERN_RANDOM,
  393.         .procname    = "random",
  394.         .mode        = 0555,
  395.         .child        = random_table,
  396.     },
  397.     {
  398.         .ctl_name    = KERN_OVERFLOWUID,
  399.         .procname    = "overflowuid",
  400.         .data        = &overflowuid,
  401.         .maxlen        = sizeof(int),
  402.         .mode        = 0644,
  403.         .proc_handler    = &proc_dointvec_minmax,
  404.         .strategy    = &sysctl_intvec,
  405.         .extra1        = &minolduid,
  406.         .extra2        = &maxolduid,
  407.     },
  408.     {
  409.         .ctl_name    = KERN_OVERFLOWGID,
  410.         .procname    = "overflowgid",
  411.         .data        = &overflowgid,
  412.         .maxlen        = sizeof(int),
  413.         .mode        = 0644,
  414.         .proc_handler    = &proc_dointvec_minmax,
  415.         .strategy    = &sysctl_intvec,
  416.         .extra1        = &minolduid,
  417.         .extra2        = &maxolduid,
  418.     },
  419. #ifdef CONFIG_S390
  420. #ifdef CONFIG_MATHEMU
  421.     {
  422.         .ctl_name    = KERN_IEEE_EMULATION_WARNINGS,
  423.         .procname    = "ieee_emulation_warnings",
  424.         .data        = &sysctl_ieee_emulation_warnings,
  425.         .maxlen        = sizeof(int),
  426.         .mode        = 0644,
  427.         .proc_handler    = &proc_dointvec,
  428.     },
  429. #endif
  430.     {
  431.         .ctl_name    = KERN_S390_USER_DEBUG_LOGGING,
  432.         .procname    = "userprocess_debug",
  433.         .data        = &sysctl_userprocess_debug,
  434.         .maxlen        = sizeof(int),
  435.         .mode        = 0644,
  436.         .proc_handler    = &proc_dointvec,
  437.     },
  438. #endif
  439.     {
  440.         .ctl_name    = KERN_PIDMAX,
  441.         .procname    = "pid_max",
  442.         .data        = &pid_max,
  443.         .maxlen        = sizeof (int),
  444.         .mode        = 0644,
  445.         .proc_handler    = &proc_dointvec_minmax,
  446.         .strategy    = sysctl_intvec,
  447.         .extra1        = &pid_max_min,
  448.         .extra2        = &pid_max_max,
  449.     },
  450.     {
  451.         .ctl_name    = KERN_PANIC_ON_OOPS,
  452.         .procname    = "panic_on_oops",
  453.         .data        = &panic_on_oops,
  454.         .maxlen        = sizeof(int),
  455.         .mode        = 0644,
  456.         .proc_handler    = &proc_dointvec,
  457.     },
  458. #if defined CONFIG_PRINTK
  459.     {
  460.         .ctl_name    = KERN_PRINTK,
  461.         .procname    = "printk",
  462.         .data        = &console_loglevel,
  463.         .maxlen        = 4*sizeof(int),
  464.         .mode        = 0644,
  465.         .proc_handler    = &proc_dointvec,
  466.     },
  467.     {
  468.         .ctl_name    = KERN_PRINTK_RATELIMIT,
  469.         .procname    = "printk_ratelimit",
  470.         .data        = &printk_ratelimit_state.interval,
  471.         .maxlen        = sizeof(int),
  472.         .mode        = 0644,
  473.         .proc_handler    = &proc_dointvec_jiffies,
  474.         .strategy    = &sysctl_jiffies,
  475.     },
  476.     {
  477.         .ctl_name    = KERN_PRINTK_RATELIMIT_BURST,
  478.         .procname    = "printk_ratelimit_burst",
  479.         .data        = &printk_ratelimit_state.burst,
  480.         .maxlen        = sizeof(int),
  481.         .mode        = 0644,
  482.         .proc_handler    = &proc_dointvec,
  483.     },
  484.     {
  485.         .ctl_name    = CTL_UNNUMBERED,
  486.         .procname    = "printk_delay",
  487.         .data        = &printk_delay_msec,
  488.         .maxlen        = sizeof(int),
  489.         .mode        = 0644,
  490.         .proc_handler    = &proc_dointvec_minmax,
  491.         .strategy    = &sysctl_intvec,
  492.         .extra1        = &zero,
  493.         .extra2        = &ten_thousand,
  494.     },
  495. #endif
  496.     {
  497.         .ctl_name    = KERN_NGROUPS_MAX,
  498.         .procname    = "ngroups_max",
  499.         .data        = &ngroups_max,
  500.         .maxlen        = sizeof (int),
  501.         .mode        = 0444,
  502.         .proc_handler    = &proc_dointvec,
  503.     },
  504. #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
  505.     {
  506.         .ctl_name = KERN_UNKNOWN_NMI_PANIC,
  507.         .procname = "unknown_nmi_panic",
  508.         .data = &unknown_nmi_panic,
  509.         .maxlen = sizeof (int),
  510.         .mode = 0644,
  511.         .proc_handler = &proc_dointvec,
  512.     },
  513.     {
  514.         .procname = "nmi_watchdog",
  515.         .data = &nmi_watchdog_enabled,
  516.         .maxlen = sizeof (int),
  517.         .mode = 0644,
  518.         .proc_handler = &proc_nmi_enabled,
  519.     },
  520. #endif
  521. #if defined(CONFIG_X86)
  522.     {
  523.         .ctl_name    = KERN_PANIC_ON_NMI,
  524.         .procname    = "panic_on_unrecovered_nmi",
  525.         .data        = &panic_on_unrecovered_nmi,
  526.         .maxlen        = sizeof(int),
  527.         .mode        = 0644,
  528.         .proc_handler    = &proc_dointvec,
  529.     },
  530.     {
  531.         .ctl_name    = CTL_UNNUMBERED,
  532.         .procname    = "panic_on_io_nmi",
  533.         .data        = &panic_on_io_nmi,
  534.         .maxlen        = sizeof(int),
  535.         .mode        = 0644,
  536.         .proc_handler    = &proc_dointvec,
  537.     },
  538.     {
  539.         .ctl_name    = KERN_BOOTLOADER_TYPE,
  540.         .procname    = "bootloader_type",
  541.         .data        = &bootloader_type,
  542.         .maxlen        = sizeof (int),
  543.         .mode        = 0444,
  544.         .proc_handler    = &proc_dointvec,
  545.     },
  546.     {
  547.         .ctl_name    = CTL_UNNUMBERED,
  548.         .procname    = "bootloader_version",
  549.         .data        = &bootloader_version,
  550.         .maxlen        = sizeof (int),
  551.         .mode        = 0444,
  552.         .proc_handler    = &proc_dointvec,
  553.     },
  554.     {
  555.         .ctl_name    = CTL_UNNUMBERED,
  556.         .procname    = "kstack_depth_to_print",
  557.         .data        = &kstack_depth_to_print,
  558.         .maxlen        = sizeof(int),
  559.         .mode        = 0644,
  560.         .proc_handler    = &proc_dointvec,
  561.     },
  562.     {
  563.         .ctl_name    = CTL_UNNUMBERED,
  564.         .procname    = "io_delay_type",
  565.         .data        = &io_delay_type,
  566.         .maxlen        = sizeof(int),
  567.         .mode        = 0644,
  568.         .proc_handler    = &proc_dointvec,
  569.     },
  570. #endif
  571. #if defined(CONFIG_MMU)
  572.     {
  573.         .ctl_name    = KERN_RANDOMIZE,
  574.         .procname    = "randomize_va_space",
  575.         .data        = &randomize_va_space,
  576.         .maxlen        = sizeof(int),
  577.         .mode        = 0644,
  578.         .proc_handler    = &proc_dointvec,
  579.     },
  580. #endif
  581. #if defined(CONFIG_S390) && defined(CONFIG_SMP)
  582.     {
  583.         .ctl_name    = KERN_SPIN_RETRY,
  584.         .procname    = "spin_retry",
  585.         .data        = &spin_retry,
  586.         .maxlen        = sizeof (int),
  587.         .mode        = 0644,
  588.         .proc_handler    = &proc_dointvec,
  589.     },
  590. #endif
  591. #if    defined(CONFIG_ACPI_SLEEP) && defined(CONFIG_X86)
  592.     {
  593.         .procname    = "acpi_video_flags",
  594.         .data        = &acpi_realmode_flags,
  595.         .maxlen        = sizeof (unsigned long),
  596.         .mode        = 0644,
  597.         .proc_handler    = &proc_doulongvec_minmax,
  598.     },
  599. #endif
  600. #ifdef CONFIG_IA64
  601.     {
  602.         .ctl_name    = KERN_IA64_UNALIGNED,
  603.         .procname    = "ignore-unaligned-usertrap",
  604.         .data        = &no_unaligned_warning,
  605.         .maxlen        = sizeof (int),
  606.          .mode        = 0644,
  607.         .proc_handler    = &proc_dointvec,
  608.     },
  609.     {
  610.         .ctl_name    = CTL_UNNUMBERED,
  611.         .procname    = "unaligned-dump-stack",
  612.         .data        = &unaligned_dump_stack,
  613.         .maxlen        = sizeof (int),
  614.         .mode        = 0644,
  615.         .proc_handler    = &proc_dointvec,
  616.     },
  617. #endif
  618. #ifdef CONFIG_DETECT_SOFTLOCKUP
  619.     {
  620.         .ctl_name    = CTL_UNNUMBERED,
  621.         .procname    = "softlockup_panic",
  622.         .data        = &softlockup_panic,
  623.         .maxlen        = sizeof(int),
  624.         .mode        = 0644,
  625.         .proc_handler    = &proc_dointvec_minmax,
  626.         .strategy    = &sysctl_intvec,
  627.         .extra1        = &zero,
  628.         .extra2        = &one,
  629.     },
  630.     {
  631.         .ctl_name    = CTL_UNNUMBERED,
  632.         .procname    = "softlockup_thresh",
  633.         .data        = &softlockup_thresh,
  634.         .maxlen        = sizeof(int),
  635.         .mode        = 0644,
  636.         .proc_handler    = &proc_dosoftlockup_thresh,
  637.         .strategy    = &sysctl_intvec,
  638.         .extra1        = &neg_one,
  639.         .extra2        = &sixty,
  640.     },
  641. #endif
  642. #ifdef CONFIG_DETECT_HUNG_TASK
  643.     {
  644.         .ctl_name    = CTL_UNNUMBERED,
  645.         .procname    = "hung_task_panic",
  646.         .data        = &sysctl_hung_task_panic,
  647.         .maxlen        = sizeof(int),
  648.         .mode        = 0644,
  649.         .proc_handler    = &proc_dointvec_minmax,
  650.         .strategy    = &sysctl_intvec,
  651.         .extra1        = &zero,
  652.         .extra2        = &one,
  653.     },
  654.     {
  655.         .ctl_name    = CTL_UNNUMBERED,
  656.         .procname    = "hung_task_check_count",
  657.         .data        = &sysctl_hung_task_check_count,
  658.         .maxlen        = sizeof(unsigned long),
  659.         .mode        = 0644,
  660.         .proc_handler    = &proc_doulongvec_minmax,
  661.         .strategy    = &sysctl_intvec,
  662.     },
  663.     {
  664.         .ctl_name    = CTL_UNNUMBERED,
  665.         .procname    = "hung_task_timeout_secs",
  666.         .data        = &sysctl_hung_task_timeout_secs,
  667.         .maxlen        = sizeof(unsigned long),
  668.         .mode        = 0644,
  669.         .proc_handler    = &proc_dohung_task_timeout_secs,
  670.         .strategy    = &sysctl_intvec,
  671.     },
  672.     {
  673.         .ctl_name    = CTL_UNNUMBERED,
  674.         .procname    = "hung_task_warnings",
  675.         .data        = &sysctl_hung_task_warnings,
  676.         .maxlen        = sizeof(unsigned long),
  677.         .mode        = 0644,
  678.         .proc_handler    = &proc_doulongvec_minmax,
  679.         .strategy    = &sysctl_intvec,
  680.     },
  681. #endif
  682. #ifdef CONFIG_COMPAT
  683.     {
  684.         .ctl_name    = KERN_COMPAT_LOG,
  685.         .procname    = "compat-log",
  686.         .data        = &compat_log,
  687.         .maxlen        = sizeof (int),
  688.          .mode        = 0644,
  689.         .proc_handler    = &proc_dointvec,
  690.     },
  691. #endif
  692. #ifdef CONFIG_RT_MUTEXES
  693.     {
  694.         .ctl_name    = KERN_MAX_LOCK_DEPTH,
  695.         .procname    = "max_lock_depth",
  696.         .data        = &max_lock_depth,
  697.         .maxlen        = sizeof(int),
  698.         .mode        = 0644,
  699.         .proc_handler    = &proc_dointvec,
  700.     },
  701. #endif
  702.     {
  703.         .ctl_name    = CTL_UNNUMBERED,
  704.         .procname    = "poweroff_cmd",
  705.         .data        = &poweroff_cmd,
  706.         .maxlen        = POWEROFF_CMD_PATH_LEN,
  707.         .mode        = 0644,
  708.         .proc_handler    = &proc_dostring,
  709.         .strategy    = &sysctl_string,
  710.     },
  711. #ifdef CONFIG_KEYS
  712.     {
  713.         .ctl_name    = CTL_UNNUMBERED,
  714.         .procname    = "keys",
  715.         .mode        = 0555,
  716.         .child        = key_sysctls,
  717.     },
  718. #endif
  719. #ifdef CONFIG_RCU_TORTURE_TEST
  720.     {
  721.         .ctl_name = CTL_UNNUMBERED,
  722.         .procname = "rcutorture_runnable",
  723.         .data = &rcutorture_runnable,
  724.         .maxlen = sizeof(int),
  725.         .mode = 0644,
  726.         .proc_handler = &proc_dointvec,
  727.     },
  728. #endif
  729. #ifdef CONFIG_SLOW_WORK
  730.     {
  731.         .ctl_name    = CTL_UNNUMBERED,
  732.         .procname    = "slow-work",
  733.         .mode        = 0555,
  734.         .child        = slow_work_sysctls,
  735.     },
  736. #endif
  737. #ifdef CONFIG_PERF_EVENTS
  738.     {
  739.         .ctl_name    = CTL_UNNUMBERED,
  740.         .procname    = "perf_event_paranoid",
  741.         .data        = &sysctl_perf_event_paranoid,
  742.         .maxlen        = sizeof(sysctl_perf_event_paranoid),
  743.         .mode        = 0644,
  744.         .proc_handler    = &proc_dointvec,
  745.     },
  746.     {
  747.         .ctl_name    = CTL_UNNUMBERED,
  748.         .procname    = "perf_event_mlock_kb",
  749.         .data        = &sysctl_perf_event_mlock,
  750.         .maxlen        = sizeof(sysctl_perf_event_mlock),
  751.         .mode        = 0644,
  752.         .proc_handler    = &proc_dointvec,
  753.     },
  754.     {
  755.         .ctl_name    = CTL_UNNUMBERED,
  756.         .procname    = "perf_event_max_sample_rate",
  757.         .data        = &sysctl_perf_event_sample_rate,
  758.         .maxlen        = sizeof(sysctl_perf_event_sample_rate),
  759.         .mode        = 0644,
  760.         .proc_handler    = &proc_dointvec,
  761.     },
  762. #endif
  763. #ifdef CONFIG_KMEMCHECK
  764.     {
  765.         .ctl_name    = CTL_UNNUMBERED,
  766.         .procname    = "kmemcheck",
  767.         .data        = &kmemcheck_enabled,
  768.         .maxlen        = sizeof(int),
  769.         .mode        = 0644,
  770.         .proc_handler    = &proc_dointvec,
  771.     },
  772. #endif
  773. #ifdef CONFIG_BLOCK
  774.     {
  775.         .ctl_name    = CTL_UNNUMBERED,
  776.         .procname    = "blk_iopoll",
  777.         .data        = &blk_iopoll_enabled,
  778.         .maxlen        = sizeof(int),
  779.         .mode        = 0644,
  780.         .proc_handler    = &proc_dointvec,
  781.     },
  782. #endif
  783. /*
  784.  * NOTE: do not add new entries to this table unless you have read
  785.  * Documentation/sysctl/ctl_unnumbered.txt
  786.  */
  787.     { .ctl_name = 0 }
  788. }
  1. #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
  2.     {
  3.         .ctl_name    = KERN_HOTPLUG,
  4.         .procname    = "hotplug",
  5.         .data        = &uevent_helper,
  6.         .maxlen        = UEVENT_HELPER_PATH_LEN,
  7.         .mode        = 0644,
  8.         .proc_handler    = &proc_dostring,
  9.         .strategy    = &sysctl_string,
  10.     },
  11. #endif

我们看到hotplug的参数是uevent_helper
那么/sys/XXX 下面的是在哪里初始化的呢?
当然它涉及sysfs .  我们看文件kernel/ksysfs.c 

点击(此处)折叠或打开

  1. static int __init ksysfs_init(void)
  2. {
  3.     int error;

  4.     kernel_kobj = kobject_create_and_add("kernel", NULL);
  5.     if (!kernel_kobj) {
  6.         error = -ENOMEM;
  7.         goto exit;
  8.     }
  9.     error = sysfs_create_group(kernel_kobj, &kernel_attr_group);
  10.     if (error)
  11.         goto kset_exit;

  12.     if (notes_size > 0) {
  13.         notes_attr.size = notes_size;
  14.         error = sysfs_create_bin_file(kernel_kobj, &notes_attr);
  15.         if (error)
  16.             goto group_exit;
  17.     }

  18.     return 0;

  19. group_exit:
  20.     sysfs_remove_group(kernel_kobj, &kernel_attr_group);
  21. kset_exit:
  22.     kobject_put(kernel_kobj);
  23. exit:
  24.     return error;
  25. }

它首先在/sys/目录下添加了kernel目录对象. 我们是否还记得uevent_helper变量? 
我们看这段代码,似乎就会明白了

点击(此处)折叠或打开

  1. #define KERNEL_ATTR_RO(_name) \
  2. static struct kobj_attribute _name##_attr = __ATTR_RO(_name)

  3. #define KERNEL_ATTR_RW(_name) \
  4. static struct kobj_attribute _name##_attr = \
  5.     __ATTR(_name, 0644, _name##_show, _name##_store)

  6. #if defined(CONFIG_HOTPLUG)
  7. /* current uevent sequence number */
  8. static ssize_t uevent_seqnum_show(struct kobject *kobj,
  9.                  struct kobj_attribute *attr, char *buf)
  10. {
  11.     return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum);
  12. }
  13. KERNEL_ATTR_RO(uevent_seqnum);

  14. /* uevent helper program, used during early boo */
  15. static ssize_t uevent_helper_show(struct kobject *kobj,
  16.                  struct kobj_attribute *attr, char *buf)
  17. {
  18.     return sprintf(buf, "%s\n", uevent_helper);
  19. }
  20. static ssize_t uevent_helper_store(struct kobject *kobj,
  21.                  struct kobj_attribute *attr,
  22.                  const char *buf, size_t count)
  23. {
  24.     if (count+> UEVENT_HELPER_PATH_LEN)
  25.         return -ENOENT;
  26.     memcpy(uevent_helper, buf, count);
  27.     uevent_helper[count] = '\0';
  28.     if (count && uevent_helper[count-1] == '\n')
  29.         uevent_helper[count-1] = '\0';
  30.     return count;
  31. }
  32. KERNEL_ATTR_RW(uevent_helper);
  33. #endif

KERNEL_ATTR_RW(uevent_helper);  对!就是它!我们在include/linux/sysfs.h中


#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
是否就和上边的代码联系起来了呢? 
我们接着看ksysfs_init:
error = sysfs_create_group(kernel_kobj, &kernel_attr_group);
kernel_attr_group是什么呢
static struct attribute_group kernel_attr_group = {
.attrs = kernel_attrs,
};
继续看kernel_attrs
static struct attribute * kernel_attrs[] = {
#if defined(CONFIG_HOTPLUG)
&uevent_seqnum_attr.attr,
&uevent_helper_attr.attr,
#endif
#ifdef CONFIG_PROFILING
&profiling_attr.attr,
#endif
#ifdef CONFIG_KEXEC
&kexec_loaded_attr.attr,
&kexec_crash_loaded_attr.attr,
&vmcoreinfo_attr.attr,
#endif
NULL
};

结合刚才看的一大堆宏定义.以及uevent_helper_store ,它用来写入uevent_helper。
既然我们知道了原理,就会少一些困惑^^. 而关于call_usermodehelper,有兴趣的可以自行分析学习.

0 0
原创粉丝点击