系统调用之sys_adjtimex

这个函数主要用于读取kernel时间,如果是superuser的话,则可以写kernel时间。
其源码分析如下:
SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
{
	struct timex txc;		/* Local copy of parameter */
	int ret;

	/* Copy the user data space into the kernel copy
	 * structure. But bear in mind that the structures
	 * may change
	 */
	#从user space copy txc_p中的内容到txc中
	if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
		return -EFAULT;
	#根据txc中的内容读写kernel时间
	ret = do_adjtimex(&txc);
	#从kernel space 中的txc中的内容copy到txc_p中
	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
}

int do_adjtimex(struct timex *txc)
{
#得到timer keeper的时间
	struct timekeeper *tk = &tk_core.timekeeper;
	unsigned long flags;
	struct timespec64 ts;
	s32 orig_tai, tai;
	int ret;

	/* Validate the data before disabling interrupts */
	#检查txc 中的时间是否合法
	ret = timekeeping_validate_timex(txc);
	if (ret)
		return ret;
	#ADJ_SETOFFSET 表示增加当前time keeper的时间
	if (txc->modes & ADJ_SETOFFSET) {
		struct timespec64 delta;
		delta.tv_sec  = txc->time.tv_sec;
		delta.tv_nsec = txc->time.tv_usec;
		if (!(txc->modes & ADJ_NANO))
			delta.tv_nsec *= 1000;
		ret = timekeeping_inject_offset(&delta);
		#正常情况下ret等于零。
		if (ret)
			return ret;
	}
	#以timespec64格式获取当前时间
	getnstimeofday64(&ts);
	#开始修改time keeper时间
	raw_spin_lock_irqsave(&timekeeper_lock, flags);
	write_seqcount_begin(&tk_core.seq);

	orig_tai = tai = tk->tai_offset;
	#根据txc和ts的时间来或者写 kernel 时间,主要给txc赋值,并通过process_adjtime_modes得到tail
	ret = __do_adjtimex(txc, &ts, &tai);
	#说明时间已经被更新了,开始update time keeper中的时间
	if (tai != orig_tai) {
		__timekeeping_set_tai_offset(tk, tai);
		timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET);
	}
	tk_update_leap_state(tk);

	write_seqcount_end(&tk_core.seq);
	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);

	if (tai != orig_tai)
		clock_was_set();
	#通知ntp时间已经被修改
	ntp_notify_cmos_timer();

	return ret;
}

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/80230134