这个函数主要用于读取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得到tailret = __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;
}