linux比较函数,linux reboot函数各分支对比分析

在linux里面,关机、重启可以通过不同的命令实现

说明:下面我贴的代码是基于linux 3.13.0版本内核的代码,和其它版本可能有一定程度的差异。

一、reboot

/*

* Reboot system call: for obvious reasons only root may call it,

* and even root needs to set up some magic numbers in the registers

* so that some mistake won't make this reboot the whole machine.

* You can also set the meaning of the ctrl-alt-del-key here.

*

* reboot doesn't sync: do that yourself before calling this.

*/

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,

void __user *, arg)

{

struct pid_namespace *pid_ns = task_active_pid_ns(current);

char buffer[256];

int ret = 0;

/* We only trust the superuser with rebooting the system. */

if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))

return -EPERM;

/* For safety, we require "magic" arguments. */

if (magic1 != LINUX_REBOOT_MAGIC1 ||

(magic2 != LINUX_REBOOT_MAGIC2 &&

magic2 != LINUX_REBOOT_MAGIC2A &&

magic2 != LINUX_REBOOT_MAGIC2B &&

magic2 != LINUX_REBOOT_MAGIC2C))

return -EINVAL;

/*

* If pid namespaces are enabled and the current task is in a child

* pid_namespace, the command is handled by reboot_pid_ns() which will

* call do_exit().

*/

ret = reboot_pid_ns(pid_ns, cmd);

if (ret)

return ret;

/* Instead of trying to make the power_off code look like

* halt when pm_power_off is not set do it the easy way.

*/

if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)

cmd = LINUX_REBOOT_CMD_HALT;

mutex_lock(&reboot_mutex);

switch (cmd) {

case LINUX_REBOOT_CMD_RESTART:

kernel_restart(NULL);

break;

case LINUX_REBOOT_CMD_CAD_ON:

C_A_D = 1;

break;

case LINUX_REBOOT_CMD_CAD_OFF:

C_A_D = 0;

break;

case LINUX_REBOOT_CMD_HALT:

kernel_halt();

do_exit(0);

panic("cannot halt");

case LINUX_REBOOT_CMD_POWER_OFF:

kernel_power_off();

do_exit(0);

break;

case LINUX_REBOOT_CMD_RESTART2:

ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);

if (ret < 0) {

ret = -EFAULT;

break;

}

buffer[sizeof(buffer) - 1] = ' ';

kernel_restart(buffer);

break;

#ifdef CONFIG_KEXEC

case LINUX_REBOOT_CMD_KEXEC:

ret = kernel_kexec();

break;

#endif

#ifdef CONFIG_HIBERNATION

case LINUX_REBOOT_CMD_SW_SUSPEND:

ret = hibernate();

break;

#endif

default:

ret = -EINVAL;

break;

}

mutex_unlock(&reboot_mutex);

return ret;

}

在第44行之前,是所有的命令都要执行的,而在本文,我们简要分析不同命令的区别;所以主要分析44行后switch的各分支。

根据switch的case分支可知,命令和函数的对应关系为:

函数指针

函数

restart

kernel_restart

poweroff

kernel_halt

suspend

kernel_power_off

suspend

hibernate

kexec

没有具体实现,略过

下面我们先把个实现函数的代码贴上来,看一下流程上的差别。

二、各分支函数预览

2.1、kernel_restart

/**

*kernel_restart - reboot the system

*@cmd: pointer to buffer containing command to execute for restart

*or %NULL

*

*Shutdown everything and perform a clean reboot.

*This is not safe to call in interrupt context.

*/

void kernel_restart(char *cmd)

{

kernel_restart_prepare(cmd);

migrate_to_reboot_cpu();

syscore_shutdown();

if (!cmd)

pr_emerg("Restarting systemn");

else

pr_emerg("Restarting system with command '%s'n", cmd);

kmsg_dump(KMSG_DUMP_RESTART);

machine_restart(cmd);

}

2.2、kernel_halt

/**

* kernel_halt - halt the system

*

* Shutdown everything and perform a clean system halt.

*/

void kernel_halt(void)

{

kernel_shutdown_prepare(SYSTEM_HALT);

migrate_to_reboot_cpu();

syscore_shutdown();

pr_emerg("System haltedn");

kmsg_dump(KMSG_DUMP_HALT);

machine_halt();

}

2.3、kernel_power_off

/**

* kernel_power_off - power_off the system

*

* Shutdown everything and perform a clean system power_off.

*/

void kernel_power_off(void)

{

kernel_shutdown_prepare(SYSTEM_POWER_OFF);

if (pm_power_off_prepare)

pm_power_off_prepare();

migrate_to_reboot_cpu();

syscore_shutdown();

pr_emerg("Power downn");

kmsg_dump(KMSG_DUMP_POWEROFF);

machine_power_off();

}

2.4、hibernate

/**

* hibernate - Carry out system hibernation, including saving the image.

*/

int hibernate(void)

{

int error;

lock_system_sleep();

/* The snapshot device should not be opened while we're running */

if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {

error = -EBUSY;

goto Unlock;

}

pm_prepare_console();

error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);

if (error)

goto Exit;

printk(KERN_INFO "PM: Syncing filesystems ... ");

sys_sync();

printk("done.n");

error = freeze_processes();

if (error)

goto Exit;

lock_device_hotplug();

/* Allocate memory management structures */

error = create_basic_memory_bitmaps();

if (error)

goto Thaw;

error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);

if (error || freezer_test_done)

goto Free_bitmaps;

if (in_suspend) {

unsigned int flags = 0;

if (hibernation_mode == HIBERNATION_PLATFORM)

flags |= SF_PLATFORM_MODE;

if (nocompress)

flags |= SF_NOCOMPRESS_MODE;

else

flags |= SF_CRC32_MODE;

pr_debug("PM: writing image.n");

error = swsusp_write(flags);

swsusp_free();

if (!error)

power_down();

in_suspend = 0;

pm_restore_gfp_mask();

} else {

pr_debug("PM: Image restored successfully.n");

}

Free_bitmaps:

free_basic_memory_bitmaps();

Thaw:

unlock_device_hotplug();

thaw_processes();

/* Don't bother checking whether freezer_test_done is true */

freezer_test_done = false;

Exit:

pm_notifier_call_chain(PM_POST_HIBERNATION);

pm_restore_console();

atomic_inc(&snapshot_device_available);

Unlock:

unlock_system_sleep();

return error;

}

看完以上四个函数的代码,可以知道,前面三个函数在流程上差别不是很大,第四个函数hibernate的流程就完全不同。

下面我们以表格的方式来整理一下前三个函数的区别。

三、reboot中各函数流程对比

函数流程对比

序号

kernel_restart

kernel_halt

kernel_power_off

1

kernel_restart_prepare

kernel_shutdown_prepare

kernel_shutdown_prepare

2

migrate_to_reboot_cpu

migrate_to_reboot_cpu

migrate_to_reboot_cpu

3

syscore_shutdown

syscore_shutdown

syscore_shutdown

4

kmsg_dump

kmsg_dump

kmsg_dump

5

machine_restart

machine_halt

machine_power_off

上面的三个函数的第2、3、4个步骤都是一样的。

而kernel_restart函数在linux关机时emmc驱动处理流程时主干代码基本分析了,所以在这里第2、3、4步骤就不再分析。

而kernel_halt和kernel_power_off的第一个步骤是一样的。

来看一下第一个步骤中kernel_restart_prepare函数和kernel_shutdown_prepare函数的源码实现。

四、prepare函数对比

4.1、kernel_restart_prepare

通过第一节中的reboot函数可以知道,reboot传递给kernel_restart的形参cmd的值为NULL;

所以kernel_restart传递给kernel_restart_prepare的参数值也为NULL,下面看一下kernel_restart_prepare的实现:

void kernel_restart_prepare(char *cmd)

{

blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);

system_state = SYSTEM_RESTART;

usermodehelper_disable();

device_shutdown();

}

需要注意的是,这里通知链传递的通知消息为SYS_RESTART。

4.2、kernel_shutdown_prepare

static void kernel_shutdown_prepare(enum system_states state)

{

blocking_notifier_call_chain(&reboot_notifier_list,

(state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);

system_state = state;

usermodehelper_disable();

device_shutdown();

}

这个函数和4.1的kernel_restart_prepare函数整体差不多,唯一不同的就是传递给通知链的第二个参数;

当调用kernel_halt传递的参数为SYS_HALT,否则传递SYS_POWER_OFF。

五、restart、halt、power_off

machine_restart、machine_halt、machine_power_off函数的实现差异比较大,我暂时还没弄懂

回到第一节,有一个hibernate函数,我们还没有分析;

这个函数的代码在2.4节已经贴出来了,涉及的代码比较多,我还没完全理解

六、休眠对于emmc的影响

第3节的device_suspend函数如下(我的源代码是3.13.0):

/**

* device_suspend - Execute "suspend" callbacks for given device.

* @dev: Device to handle.

* @state: PM transition of the system being carried out.

* @async: If true, the device is being suspended asynchronously.

*/

static int __device_suspend(struct device *dev, pm_message_t state, bool async)

{

pm_callback_t callback = NULL;

char *info = NULL;

int error = 0;

DECLARE_DPM_WATCHDOG_ON_STACK(wd);

dpm_wait_for_children(dev, async);

if (async_error)

goto Complete;

/*

* If a device configured to wake up the system from sleep states

* has been suspended at run time and there's a resume request pending

* for it, this is equivalent to the device signaling wakeup, so the

* system suspend operation should be aborted.

*/

if (pm_runtime_barrier(dev) && device_may_wakeup(dev))

pm_wakeup_event(dev, 0);

if (pm_wakeup_pending()) {

async_error = -EBUSY;

goto Complete;

}

if (dev->power.syscore)

goto Complete;

dpm_watchdog_set(&wd, dev);

device_lock(dev);

if (dev->pm_domain) {

info = "power domain ";

callback = pm_op(&dev->pm_domain->ops, state);

goto Run;

}

if (dev->type && dev->type->pm) {

info = "type ";

callback = pm_op(dev->type->pm, state);

goto Run;

}

if (dev->class) {

if (dev->class->pm) {

info = "class ";

callback = pm_op(dev->class->pm, state);

goto Run;

} else if (dev->class->suspend) {

pm_dev_dbg(dev, state, "legacy class ");

error = legacy_suspend(dev, state, dev->class->suspend,

"legacy class ");

goto End;

}

}

if (dev->bus) {

if (dev->bus->pm) {

info = "bus ";

callback = pm_op(dev->bus->pm, state);

} else if (dev->bus->suspend) {

pm_dev_dbg(dev, state, "legacy bus ");

error = legacy_suspend(dev, state, dev->bus->suspend,

"legacy bus ");

goto End;

}

}

Run:

if (!callback && dev->driver && dev->driver->pm) {

info = "driver ";

callback = pm_op(dev->driver->pm, state);

}

error = dpm_run_callback(callback, dev, state, info);

End:

if (!error) {

dev->power.is_suspended = true;

if (dev->power.wakeup_path

&& dev->parent && !dev->parent->power.ignore_children)

dev->parent->power.wakeup_path = true;

}

device_unlock(dev);

dpm_watchdog_clear(&wd);

Complete:

complete_all(&dev->power.completion);

if (error)

async_error = error;

return error;

}

通过追溯源代码,我们可以知道,当系统在深度休眠时传递给此函数的state参数为:PM_EVENT_SUSPEND。

第51行:如果设备注册了pm函数集指针就执行设备的函数集指针,否则执行第64行的函数集指针;从我们的emmc驱动来看,它没有注册设备的函数集指针,但是有注册总线的pm函数集指针,在bus.c文件中有如下代码:

static struct bus_type mmc_bus_type = {

.name= "mmc",

.dev_groups= mmc_dev_groups,

.match= mmc_bus_match,

.uevent= mmc_bus_uevent,

.probe= mmc_bus_probe,

.remove= mmc_bus_remove,

.shutdown= mmc_bus_shutdown,

.pm= &mmc_bus_pm_ops,

};

而mmc_bus_pm_ops的实现如下:

static const struct dev_pm_ops mmc_bus_pm_ops = {

SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume,

mmc_runtime_idle)

SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)

};

SET_RUNTIME_PM_OPS宏的实现如下:

#ifdef CONFIG_PM_RUNTIME

#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)

.runtime_suspend = suspend_fn,

.runtime_resume = resume_fn,

.runtime_idle = idle_fn,

#else

#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)

#endif

SET_SYSTEM_SLEEP_PM_OPS的实现如下:

#ifdef CONFIG_PM_SLEEP

#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)

.suspend = suspend_fn,

.resume = resume_fn,

.freeze = suspend_fn,

.thaw = resume_fn,

.poweroff = suspend_fn,

.restore = resume_fn,

#else

#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)

#endif

__device_suspend函数的第67行:callback = pm_op(dev->class->pm, state);代码展开:

/**

* pm_op - Return the PM operation appropriate for given PM event.

* @ops: PM operations to choose from.

* @state: PM transition of the system being carried out.

*/

static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state)

{

switch (state.event) {

#ifdef CONFIG_SUSPEND

case PM_EVENT_SUSPEND:

return ops->suspend;

case PM_EVENT_RESUME:

return ops->resume;

#endif /* CONFIG_SUSPEND */

#ifdef CONFIG_HIBERNATE_CALLBACKS

case PM_EVENT_FREEZE:

case PM_EVENT_QUIESCE:

return ops->freeze;

case PM_EVENT_HIBERNATE:

return ops->poweroff;

case PM_EVENT_THAW:

case PM_EVENT_RECOVER:

return ops->thaw;

break;

case PM_EVENT_RESTORE:

return ops->restore;

#endif /* CONFIG_HIBERNATE_CALLBACKS */

}

return NULL;

}

而在本节的前面,我们知道__device_suspend的参数state值为PM_EVENT_SUSPEND。

所以,这里执行的就是emmc驱动模块的bus.c中的mmc_bus_suspend函数:

static int mmc_bus_suspend(struct device *dev)

{

struct mmc_driver *drv = to_mmc_driver(dev->driver);

struct mmc_card *card = mmc_dev_to_card(dev);

struct mmc_host *host = card->host;

int ret;

if (dev->driver && drv->suspend) {

ret = drv->suspend(card);

if (ret)

return ret;

}

ret = host->bus_ops->suspend(host);

return ret;

}

而该函数最终调用的是驱动的suspend和总线ops的suspend;

在emmc驱动的block.c文件中,驱动的suspend函数指针指向mmc_blk_suspend函数,实现如下:

static int mmc_blk_suspend(struct mmc_card *card)

{

return _mmc_blk_suspend(card);

}

而_mmc_blk_suspend在第七节我们详细讲解过,这里就不再重复。

在emmc驱动模块的bus.c文件中,我们知道总线ops的suspend函数,是指向mmc_suspend函数,实现如下:

static int mmc_suspend(struct mmc_host *host)

{

int err;

err = _mmc_suspend(host, true);

if (!err) {

pm_runtime_disable(&host->card->dev);

pm_runtime_set_suspended(&host->card->dev);

}

return err;

}

由此,我们可以知道,其实它是依赖于_mmc_suspend函数的,而_mmc_suspend函数我们在第十一节中详细描述过,这里也不再描述。

本节总结:系统休眠对emmc的影响:

1、将消息对列挂载起来,暂时不执行,并没有发送什么命令

2、如果设备是挂载状态,则直接返回,否则执行下面的流程:

3、如果设备当前正在执行块请求操作,则发送停止块请求操作(停止编程操作),会涉及到以下命令:

MMC_SLEEP_AWAKE 5/* ac [31:16] RCA 15:flg R1b */

MMC_SWITCH 6/* ac [31:0] See below R1b */

MMC_SELECT_CARD 7/* ac [31:16] RCA

#define MMC_STOP_TRANSMISSION 12 /* ac R1b */

#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */

4、将缓存数据写到卡上,发送MMC_SWITCH 命令。

5、根据emmc的当前状态,可能会发送CMD6设置host状态为poweroff状态,或者是发送CMD1命令进入休眠,或者是发送CMD7命令设置host与card的断开;

6、通过设置设备的ocr寄存器设置设备断电。

7、设置设备为挂载状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值