diff mbox

[1/2] posix clocks: introduce a syscall for clock tuning.

Message ID 7f4815cdfcf5bc49df4bdd09d59a4f56ca2598f5.1283504065.git.richard.cochran@omicron.at
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Richard Cochran Sept. 3, 2010, 9:29 a.m. UTC
A new syscall is introduced that allows tuning of a POSIX clock. The
syscall is implemented for four architectures: arm, blackfin, powerpc,
and x86.

The new syscall, clock_adjtime, takes two parameters, the clock ID,
and a pointer to a struct timex. The semantics of the timex struct
have been expanded by one additional mode flag, which allows an
absolute offset correction. When specificied, the clock offset is
immediately corrected by skipping to the new time value.

In addition, the POSIX clock code has been augmented to offer a
dynamic clock creation method. Instead of registering a hard
coded clock ID, modules may call create_posix_clock(), which
returns a new clock ID.

Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
---
 arch/arm/include/asm/unistd.h      |    1 +
 arch/arm/kernel/calls.S            |    1 +
 arch/blackfin/include/asm/unistd.h |    3 +-
 arch/blackfin/mach-common/entry.S  |    1 +
 arch/powerpc/include/asm/systbl.h  |    1 +
 arch/powerpc/include/asm/unistd.h  |    3 +-
 arch/x86/ia32/ia32entry.S          |    1 +
 arch/x86/include/asm/unistd_32.h   |    3 +-
 arch/x86/include/asm/unistd_64.h   |    2 +
 arch/x86/kernel/syscall_table_32.S |    1 +
 include/linux/posix-timers.h       |   10 +++-
 include/linux/syscalls.h           |    2 +
 include/linux/time.h               |    2 +
 include/linux/timex.h              |    3 +-
 kernel/compat.c                    |  136 +++++++++++++++++++++++-------------
 kernel/posix-cpu-timers.c          |    4 +
 kernel/posix-timers.c              |   58 +++++++++++++--
 17 files changed, 172 insertions(+), 60 deletions(-)

Comments

Richard Cochran Sept. 3, 2010, 9:58 a.m. UTC | #1
On Fri, Sep 03, 2010 at 11:29:05AM +0200, Richard Cochran wrote:
> +long compat_sys_clock_adjtime(clockid_t which_clock,
> +		struct compat_timex __user *utp)
> +{
> +	struct timex txc;
> +	mm_segment_t oldfs;
> +	int err, ret;
> +
> +	err = compat_get_timex(&txc, utp);
> +	if (err)
> +		return err;
> +
> +	oldfs = get_fs();
> +	set_fs(KERNEL_DS);
> +	ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
> +	set_fs(oldfs);

I don't know what the purpose of get_fs, set_fs is, but the other
clock_ functions have it that way. The adjtimex call does not have
this at all, so I ask, do we need this here, or not?

Thanks,
Richard
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Cochran Sept. 4, 2010, 2:06 p.m. UTC | #2
On Fri, Sep 03, 2010 at 11:29:05AM +0200, Richard Cochran wrote:
> A new syscall is introduced that allows tuning of a POSIX clock. The
> syscall is implemented for four architectures: arm, blackfin, powerpc,
> and x86.
> 
> The new syscall, clock_adjtime, takes two parameters, the clock ID,
> and a pointer to a struct timex. The semantics of the timex struct
> have been expanded by one additional mode flag, which allows an
> absolute offset correction. When specificied, the clock offset is
> immediately corrected by skipping to the new time value.

Sorry, last sentence should read, "corrected by adding the given time
value to the current time value."

Richard
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Gleixner Sept. 9, 2010, 10:49 a.m. UTC | #3
On Fri, 3 Sep 2010, Richard Cochran wrote:

This patch needs to be split in pieces. The syscall change is totally
unrelated to the dynamic clock id creation. Though I do not like
either of them. :)

> A new syscall is introduced that allows tuning of a POSIX clock. The
> syscall is implemented for four architectures: arm, blackfin, powerpc,
> and x86.
> 
> The new syscall, clock_adjtime, takes two parameters, the clock ID,
> and a pointer to a struct timex. The semantics of the timex struct
> have been expanded by one additional mode flag, which allows an
> absolute offset correction. When specificied, the clock offset is
> immediately corrected by skipping to the new time value.

And why do we need a separate syscall for this?

> In addition, the POSIX clock code has been augmented to offer a
> dynamic clock creation method. Instead of registering a hard
> coded clock ID, modules may call create_posix_clock(), which
> returns a new clock ID.

This has been discussed for years and I still fail to see the
requirement for this. The only result is that it allows folks to
create their special purpose clock stuff and keep it out of tree
instead of fixing the problems they have with the existing clock
infrastructure in the kernel.

As far as I understood from the previous discussions, the final goal
is to provide PTP support, right?

But what I see is an approach which tries to implement disconnected
special purpose clocks which have the ability to be adjusted
independently. What's the purpose of this ? Why can't we just use the
existing clocks and make PTP work on them ?

I know that lots of embedded folks think that they need their special
timers and extra magic to make stuff work, but that's the wrong
approach.

What's wrong with the existing clocks? Nothing, except that we have no
way to sync CLOCK_MONOTONIC across several machines. And that's what
you really want if you try to do distributed control and data
acquisition stuff.

That's a single CLOCK_MONOTONIC_GLOBAL and not a bunch of completely
disconnected clock implementations with random clock ids and random
feature sets.

Thoughts ?


	 tglx
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Cochran Sept. 9, 2010, 1:34 p.m. UTC | #4
On Thu, Sep 09, 2010 at 12:49:27PM +0200, Thomas Gleixner wrote:
> On Fri, 3 Sep 2010, Richard Cochran wrote:
> 
> This patch needs to be split in pieces. The syscall change is totally
> unrelated to the dynamic clock id creation. Though I do not like
> either of them. :)

That is not a problem. Splitting up the patch, I mean.

> > A new syscall is introduced that allows tuning of a POSIX clock. The
> > syscall is implemented for four architectures: arm, blackfin, powerpc,
> > and x86.
> > 
> > The new syscall, clock_adjtime, takes two parameters, the clock ID,
> > and a pointer to a struct timex. The semantics of the timex struct
> > have been expanded by one additional mode flag, which allows an
> > absolute offset correction. When specificied, the clock offset is
> > immediately corrected by skipping to the new time value.
> 
> And why do we need a separate syscall for this?

Because we cannot, in general, offer PTP hardware clocks as clock
sources. We need to tune the PTP hardware clock, even if there is no
connection to the Linux kernel system time.

> > In addition, the POSIX clock code has been augmented to offer a
> > dynamic clock creation method. Instead of registering a hard
> > coded clock ID, modules may call create_posix_clock(), which
> > returns a new clock ID.
> 
> This has been discussed for years and I still fail to see the
> requirement for this. The only result is that it allows folks to
> create their special purpose clock stuff and keep it out of tree
> instead of fixing the problems they have with the existing clock
> infrastructure in the kernel.

Do you have any pointers to this discussion?

> But what I see is an approach which tries to implement disconnected
> special purpose clocks which have the ability to be adjusted
> independently. What's the purpose of this ? Why can't we just use the
> existing clocks and make PTP work on them ?
> 
> I know that lots of embedded folks think that they need their special
> timers and extra magic to make stuff work, but that's the wrong
> approach.

Its not just embedded who want better synchronization, but also big
iron for microtrading on Wall Street, for example.

> What's wrong with the existing clocks? Nothing, except that we have no
> way to sync CLOCK_MONOTONIC across several machines. And that's what
> you really want if you try to do distributed control and data
> acquisition stuff.
> 
> That's a single CLOCK_MONOTONIC_GLOBAL and not a bunch of completely
> disconnected clock implementations with random clock ids and random
> feature sets.
> 
> Thoughts ?

There isn't really anything wrong with the existing clock
infrastructure, in my view. I think the stumbling block is the idea
that there can be more than one clock in a computer system, and that
user space needs access to more than just one of them.

It is a fact that PTP hardware clocks are separate from the system
clock, and this situation will presist for some time, if not
indefinitely. It is ironic that the very best PTP clocks, the PHY
clocks, are the farthest away from the system clock.

Using PTP (or any disributed time protocol, eg NTP) involves a number
of options and choices. This complexity belongs in user space. The
kernel should simply offer a way to access the hardware clocks
(mechanism, not policy). For NTP, the kernel has to have a special
role running the clock servo, but this is an exception.

Of course, the kernel wants to present a consistent system time to
user space, hiding the ugly clock details. However, when it comes to
PTP hardware clocks, the kernel needs a little help.  Only one
program, lets call it the ptpd, needs to know about the PTP
clock. What this program does depends on the operational mode and on
the user's preferences.

What follows uses the posix clock api idea just to illustrate. You
could just as well use chardev ioctls. I am not arguing about the
API. Rather I am trying to explain why the kernel must expose multiple
clocks to user space.

1. Master with external time source (like GPS)

   Using the PPS subsystem, the system time is latched on the 1 PPS
   from the GPS. Using the PTP external timestamp feature, the PTP
   clock time is also latched.  The ptpd then adjusts *both* the
   kernel time and the PTP clock time.

   systime = get_pps();
   adj = servo(systime);
   clock_adjtime(clock_realtime, adj);

   ptptime = ptp_external_timestamp();
   adj = servo(ptptime);
   clock_adjtime(clock_ptp, adj);

2. Master with PTP clock as time source

   In this case, there is no external reference clock, and we know
   that the PTP clock's oscillator is more stable than the
   system's. The ptpd enables the 1 PPS from the PTP clock and adjusts
   the system clock according to the latched system time.

   t = get_pps();
   adj = servo(t);
   clock_adjtime(clock_realtime, adj);

3. Master with kernel as time source

   In this case, we are using the system time (which could be from an
   oven quartz, for example). The ptpd enables the 1 PPS from the PTP
   clock and adjusts the PTP clock according to the latched system
   time.

   t = get_pps();
   adj = servo(t);
   clock_adjtime(clock_ptp, adj);

4. Slave with PPS hook

   Here we want to synchronize the system and the PTP clock to a
   remote clock. The ptpd uses timestamps on network packets to feed a
   servo that controls the PTP clock. The ptpd also enables the 1 PPS
   from the PTP clock and adjusts the system clock according to the
   latched system time (like case 2).

In all of these examples, most userland programs will not be aware of
what is going on, just like when NTP is used. Only the ptpd knows that
there are multiple clocks, and that program really *does* need access
to the various clocks.

Finally, there is one case which is dumb from a hardware design point
of view, but still possible. Lets say that we have a PHY based PTP
clock witnout any interrupt to the CPU. You could still use such a
computer in a distributed application by just ignoring the wrong
system time, provided that the kernel offers a way to control the PTP
hardware clock.

Richard
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Gleixner Sept. 9, 2010, 8:10 p.m. UTC | #5
Richard,

On Thu, 9 Sep 2010, Richard Cochran wrote:

> On Thu, Sep 09, 2010 at 12:49:27PM +0200, Thomas Gleixner wrote:
> > On Fri, 3 Sep 2010, Richard Cochran wrote:
> > > In addition, the POSIX clock code has been augmented to offer a
> > > dynamic clock creation method. Instead of registering a hard
> > > coded clock ID, modules may call create_posix_clock(), which
> > > returns a new clock ID.
> > 
> > This has been discussed for years and I still fail to see the
> > requirement for this. The only result is that it allows folks to
> > create their special purpose clock stuff and keep it out of tree
> > instead of fixing the problems they have with the existing clock
> > infrastructure in the kernel.
> 
> Do you have any pointers to this discussion?

Not out of the box. Need to ask the oracle of google [ I wonder if
this expression is politically correct today :) ]

My personal stance on this is clear: Assign fixed ID.

The point is, that if we provide something like CLOCK_PTP, then we can
abstract the real hardware drivers behind this clock id and we get a
consistent feature set for these drivers and a consistent behaviour on
the user space interface. There still might be a hardware driver which
cannot provide a specific feature, but there is nothing wrong to
return -ENOSYS in such a case.

> There isn't really anything wrong with the existing clock
> infrastructure, in my view. I think the stumbling block is the idea
> that there can be more than one clock in a computer system, and that
> user space needs access to more than just one of them.
> 
> It is a fact that PTP hardware clocks are separate from the system
> clock, and this situation will presist for some time, if not
> indefinitely. It is ironic that the very best PTP clocks, the PHY
> clocks, are the farthest away from the system clock.

In terms of hardware, yes.
 
> Using PTP (or any disributed time protocol, eg NTP) involves a number
> of options and choices. This complexity belongs in user space. The
> kernel should simply offer a way to access the hardware clocks
> (mechanism, not policy). For NTP, the kernel has to have a special

I completely agree with that.

> role running the clock servo, but this is an exception.
> 
> Of course, the kernel wants to present a consistent system time to
> user space, hiding the ugly clock details. However, when it comes to
> PTP hardware clocks, the kernel needs a little help.  Only one
> program, lets call it the ptpd, needs to know about the PTP
> clock. What this program does depends on the operational mode and on
> the user's preferences.

No objections
 
> What follows uses the posix clock api idea just to illustrate. You
> could just as well use chardev ioctls. I am not arguing about the
> API. Rather I am trying to explain why the kernel must expose multiple
> clocks to user space.
> 
> 1. Master with external time source (like GPS)
> 2. Master with PTP clock as time source
> 3. Master with kernel as time source
> 4. Slave with PPS hook

Ok, that makes a lot of sense now. Thanks for taking the time and
shedding some light on me!

So you want to utilize the posix-timer infrastructure to make all this
happen. This new clock basically needs clock_[get|set]time plus the
new clock_adjust syscall, nothing more. The normal application stuff
will still use what's already there, right ?

If that's the case, then I'm not going to stand in the way, except for
some implementation details like the new syscall clock_adjust: 

Please make this thing new from ground up and not just a modified copy
of sys_adjtimex.

 1) This avoids the compat syscall crap

 2) It allows you to add the extra control stuff for your PTP magic
     (PPS, whatever) which you would need to expose by some other
     means otherwise.

Thanks,

	tglx
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
john stultz Sept. 9, 2010, 9:01 p.m. UTC | #6
On Thu, 2010-09-09 at 12:49 +0200, Thomas Gleixner wrote:
> On Fri, 3 Sep 2010, Richard Cochran wrote:
> 
> This patch needs to be split in pieces. The syscall change is totally
> unrelated to the dynamic clock id creation. Though I do not like
> either of them. :)
> 
> > A new syscall is introduced that allows tuning of a POSIX clock. The
> > syscall is implemented for four architectures: arm, blackfin, powerpc,
> > and x86.
> > 
> > The new syscall, clock_adjtime, takes two parameters, the clock ID,
> > and a pointer to a struct timex. The semantics of the timex struct
> > have been expanded by one additional mode flag, which allows an
> > absolute offset correction. When specificied, the clock offset is
> > immediately corrected by skipping to the new time value.
> 
> And why do we need a separate syscall for this?
> 
> > In addition, the POSIX clock code has been augmented to offer a
> > dynamic clock creation method. Instead of registering a hard
> > coded clock ID, modules may call create_posix_clock(), which
> > returns a new clock ID.
> 
> This has been discussed for years and I still fail to see the
> requirement for this. The only result is that it allows folks to
> create their special purpose clock stuff and keep it out of tree
> instead of fixing the problems they have with the existing clock
> infrastructure in the kernel.
> 
> As far as I understood from the previous discussions, the final goal
> is to provide PTP support, right?
> 
> But what I see is an approach which tries to implement disconnected
> special purpose clocks which have the ability to be adjusted
> independently. What's the purpose of this ? Why can't we just use the
> existing clocks and make PTP work on them ?

So this too was my initial gut response. It seems ridiculous to expose
two clock_ids (CLOCK_REALTIME and CLOCK_PTP)that conceptually represent
the same thing (ie: number of seconds,nanoseconds since 1970).

It doesn't help that one of the use cases that Richard suggests is "for
example in an embedded control application. The userland software can
simply ignore the wrong system time." 

As someone who's spent a *lot* of time trying to fix the "wrong system
time" these use cases reek of work-around solutions instead of properly
fixing whatever keeps the system time from being accurately sycned.

However, as I've worked on understanding the issue, I realize that there
is some validity to needing to expose more then one hardware clock the
conceptually is the same as CLOCK_REALTIME. And that most of my gut
reaction to this was me being a bit oversensitive. :)

> I know that lots of embedded folks think that they need their special
> timers and extra magic to make stuff work, but that's the wrong
> approach.
> 
> What's wrong with the existing clocks? Nothing, except that we have no
> way to sync CLOCK_MONOTONIC across several machines. And that's what
> you really want if you try to do distributed control and data
> acquisition stuff.

Err.. s/CLOCK_MONOTONIC/CLOCK_REALTIME/ :)

> That's a single CLOCK_MONOTONIC_GLOBAL and not a bunch of completely
> disconnected clock implementations with random clock ids and random
> feature sets.

Specifically, because the way the correction feedback loops work with
PTP, working against the hardware clock that is generating the
timestamps directly is going to get the best results. 

Additionally, it allows multiple syncing methods to be tried in
userland, rather then trying jam it all in the kernel in order to make
it look like there is only one global system time. The parallel with
audio hardware is also valid, as we currently ignore any skew between
audio hardware clocks and system time, as there's no useful way to
expose those clocks (that I'm aware of atleast, not too familiar with
alsa, but my googling didn't show much).

However, since there may be multiple PTP clocks or audio clocks or
whatever, allocating static clockids for each type isn't quite useful,
as we need to deal with mapping the clockids to hardware. So exposing
the clockids via sysfs allows us to understand the physical mapping of
what bus and device the clock hangs off of.

Now, I'm not a fan of the clockid directory that Richard proposed, I'd
rather add a clock_id to the devices sysfs entry. But these are details
and can be worked out as the patch gets refined.


thanks
-john

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Gleixner Sept. 9, 2010, 9:16 p.m. UTC | #7
On Thu, 9 Sep 2010, Thomas Gleixner wrote:
> On Thu, 9 Sep 2010, Richard Cochran wrote:
> 
> > On Thu, Sep 09, 2010 at 12:49:27PM +0200, Thomas Gleixner wrote:
> > > On Fri, 3 Sep 2010, Richard Cochran wrote:
> > > > In addition, the POSIX clock code has been augmented to offer a
> > > > dynamic clock creation method. Instead of registering a hard
> > > > coded clock ID, modules may call create_posix_clock(), which
> > > > returns a new clock ID.
> > > 
> > > This has been discussed for years and I still fail to see the
> > > requirement for this. The only result is that it allows folks to
> > > create their special purpose clock stuff and keep it out of tree
> > > instead of fixing the problems they have with the existing clock
> > > infrastructure in the kernel.
> > 
> > Do you have any pointers to this discussion?
> 
> Not out of the box. Need to ask the oracle of google [ I wonder if
> this expression is politically correct today :) ]
> 
> My personal stance on this is clear: Assign fixed ID.
> 
> The point is, that if we provide something like CLOCK_PTP, then we can
> abstract the real hardware drivers behind this clock id and we get a
> consistent feature set for these drivers and a consistent behaviour on
> the user space interface. There still might be a hardware driver which
> cannot provide a specific feature, but there is nothing wrong to
> return -ENOSYS in such a case.

Hmm. Talked to John Stultz about this and got enlightened that there
might be more than one of these beasts. That changes the story
slightly.
 
So yes, I've been wrong as usual and we'll need some way of assigning
those ids dynamically, but I'm still opposed to providing an
unconfined "give me one of those id's" interface for public
consumption.

I'd rather see a controlled environment for device classes like PTP
clocks. That would have a couple of advantages:

 - clear association of the device to a well defined functionality

 - avoidance of duplicated code

 - consistent sysfs interfaces for functionality which is device class
   specific

 - simpler identification for interested applications

 - preventing the random spread of clock id consumers

So the clock device class code would provide the interface for these
class specific hardware drivers and consult the posix timer core code
to give out an id.

And that would apply to any other class of clock devices which do not
fall into the general clocksource category (e.g. RTCs, audio clocks
..)

Thoughts ?

	 tglx
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Gleixner Sept. 9, 2010, 9:31 p.m. UTC | #8
On Thu, 9 Sep 2010, john stultz wrote:
> On Thu, 2010-09-09 at 12:49 +0200, Thomas Gleixner wrote:
> > But what I see is an approach which tries to implement disconnected
> > special purpose clocks which have the ability to be adjusted
> > independently. What's the purpose of this ? Why can't we just use the
> > existing clocks and make PTP work on them ?
> 
> So this too was my initial gut response. It seems ridiculous to expose
> two clock_ids (CLOCK_REALTIME and CLOCK_PTP)that conceptually represent
> the same thing (ie: number of seconds,nanoseconds since 1970).
> 
> It doesn't help that one of the use cases that Richard suggests is "for
> example in an embedded control application. The userland software can
> simply ignore the wrong system time." 
> 
> As someone who's spent a *lot* of time trying to fix the "wrong system
> time" these use cases reek of work-around solutions instead of properly
> fixing whatever keeps the system time from being accurately sycned.
> 
> However, as I've worked on understanding the issue, I realize that there
> is some validity to needing to expose more then one hardware clock the
> conceptually is the same as CLOCK_REALTIME. And that most of my gut
> reaction to this was me being a bit oversensitive. :)

Yup. It still scares me that we might end up with a dozen different
notions of ONE second elapsed on the same machine :)

> However, since there may be multiple PTP clocks or audio clocks or
> whatever, allocating static clockids for each type isn't quite useful,

Yeah, I corrected myself on that one, but I really want to see some
confinement into well defined clock classes rather than the "hooray
here is my clock of the day" approach.

Thanks,

	tglx
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
john stultz Sept. 9, 2010, 10:53 p.m. UTC | #9
On Thu, 2010-09-09 at 23:16 +0200, Thomas Gleixner wrote:
> Hmm. Talked to John Stultz about this and got enlightened that there
> might be more than one of these beasts. That changes the story
> slightly.
> 
> So yes, I've been wrong as usual and we'll need some way of assigning
> those ids dynamically, but I'm still opposed to providing an
> unconfined "give me one of those id's" interface for public
> consumption.
> 
> I'd rather see a controlled environment for device classes like PTP
> clocks. That would have a couple of advantages:
> 
>  - clear association of the device to a well defined functionality
> 
>  - avoidance of duplicated code
> 
>  - consistent sysfs interfaces for functionality which is device class
>    specific
> 
>  - simpler identification for interested applications
> 
>  - preventing the random spread of clock id consumers
> 
> So the clock device class code would provide the interface for these
> class specific hardware drivers and consult the posix timer core code
> to give out an id.
> 
> And that would apply to any other class of clock devices which do not
> fall into the general clocksource category (e.g. RTCs, audio clocks
> ..)
> 
> Thoughts ?

So at first I was concerned, because I thought you were suggesting we
distinguish between the classes of clocks in our userspace interface. 

But after some clarification on IRC, you made it clear that you want
some generic infrastructure that supports what the PTP driver needs that
would then be re-usable by other clocks we want to similarly expose to
userland via a clockid.

So basically you want something akin to the struct clocksource for the
driver to register that would minimize code duplication.

My initial reaction, is that we already have the k_clock structure (from
include/linux/posix-timers.h):
struct k_clock {
	int res;		/* in nanoseconds */
	int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
	int (*clock_set) (const clockid_t which_clock, struct timespec * tp);
	int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
	int (*timer_create) (struct k_itimer *timer);
	int (*nsleep) (const clockid_t which_clock, int flags,
		       struct timespec *, struct timespec __user *);
	long (*nsleep_restart) (struct restart_block *restart_block);
	int (*timer_set) (struct k_itimer * timr, int flags,
			  struct itimerspec * new_setting,
			  struct itimerspec * old_setting);
	int (*timer_del) (struct k_itimer * timr);
	void (*timer_get) (struct k_itimer * timr,
			   struct itimerspec * cur_setting);
};


This is still very close to the level of the posix clocks/timers api, so
maybe you're wanting something a little lower level, possibly as low as
the clocksource/clockevent structures? 

The only problem there is from the examples, it seems some PTP hardware
can be fairly self-contained. So its a actual ns clock that can be freq
adjusted in hardware, not a constant freq counter that is then converted
to nanoseconds and freq managed in software. So the interface probably
can't be quite as low-level as the clocksource/clockevent structures.

In fact, from the example drivers posted already, it looks like the
k_clock structure maps fairly close to what the hardware uses.

Other clock types that we may want to expose, such as the RTC also can
map fairly close to k_clock. The audio clocks may need some research, as
I suspect they're just a clocksource style counter, so some additional
software cycle->ns layering similar to the timekeeping core (but likely
much simpler) may be needed.

So the question to Richard is, what does the above k_clock not provide
that the PTP driver needs?  If you've already made some stabs at it,
seeing an example of the generic header and a trivial example driver
that includes the k_clock structure, so we can see what it removed from
your earlier chardev implementation would be helpful.

thanks
-john


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Richard Cochran Sept. 10, 2010, 9:23 a.m. UTC | #10
On Thu, Sep 09, 2010 at 03:53:13PM -0700, john stultz wrote:
> The only problem there is from the examples, it seems some PTP hardware
> can be fairly self-contained. So its a actual ns clock that can be freq
> adjusted in hardware, not a constant freq counter that is then converted
> to nanoseconds and freq managed in software. So the interface probably
> can't be quite as low-level as the clocksource/clockevent structures.
> 
> In fact, from the example drivers posted already, it looks like the
> k_clock structure maps fairly close to what the hardware uses.

Yes, thats right. The PTP hardware clocks of which I know all follow
the same pattern.

> Other clock types that we may want to expose, such as the RTC also can
> map fairly close to k_clock. The audio clocks may need some research, as
> I suspect they're just a clocksource style counter, so some additional
> software cycle->ns layering similar to the timekeeping core (but likely
> much simpler) may be needed.

We may also find clocks that are free running counters which can
timestamp network packets. In that case, one would also need software
support to implement rate adjustment. I have not seen that yet among
PTP hardware clocks, so I think we should cross that bridge when we
come to it. In any case, the proposed infrastructure does not exclude
the possibility to support that kind of clock.

> So the question to Richard is, what does the above k_clock not provide
> that the PTP driver needs?

Yes.

> If you've already made some stabs at it,
> seeing an example of the generic header and a trivial example driver
> that includes the k_clock structure, so we can see what it removed from
> your earlier chardev implementation would be helpful.

Okay, it seems that we are gradually coming around to a workable
solution. I will repost the posix clock idea including the PTP clock
drivers, so you all can see how it would fit together.

Thanks,
Richard
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index dd2bf53..6bea0b7 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -392,6 +392,7 @@ 
 #define __NR_rt_tgsigqueueinfo		(__NR_SYSCALL_BASE+363)
 #define __NR_perf_event_open		(__NR_SYSCALL_BASE+364)
 #define __NR_recvmmsg			(__NR_SYSCALL_BASE+365)
+#define __NR_clock_adjtime		(__NR_SYSCALL_BASE+366)
 
 /*
  * The following SWIs are ARM private.
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 37ae301..8a22fdd 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -375,6 +375,7 @@ 
 		CALL(sys_rt_tgsigqueueinfo)
 		CALL(sys_perf_event_open)
 /* 365 */	CALL(sys_recvmmsg)
+		CALL(sys_clock_adjtime)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h
index 22886cb..6671913 100644
--- a/arch/blackfin/include/asm/unistd.h
+++ b/arch/blackfin/include/asm/unistd.h
@@ -389,8 +389,9 @@ 
 #define __NR_rt_tgsigqueueinfo	368
 #define __NR_perf_event_open	369
 #define __NR_recvmmsg		370
+#define __NR_clock_adjtime	371
 
-#define __NR_syscall		371
+#define __NR_syscall		372
 #define NR_syscalls		__NR_syscall
 
 /* Old optional stuff no one actually uses */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index a5847f5..252f2fa 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1628,6 +1628,7 @@  ENTRY(_sys_call_table)
 	.long _sys_rt_tgsigqueueinfo
 	.long _sys_perf_event_open
 	.long _sys_recvmmsg		/* 370 */
+	.long _sys_clock_adjtime
 
 	.rept NR_syscalls-(.-_sys_call_table)/4
 	.long _sys_ni_syscall
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index a5ee345..e7dce86 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -326,3 +326,4 @@  SYSCALL_SPU(perf_event_open)
 COMPAT_SYS_SPU(preadv)
 COMPAT_SYS_SPU(pwritev)
 COMPAT_SYS(rt_tgsigqueueinfo)
+COMPAT_SYS_SPU(clock_adjtime)
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index f0a1026..7d4d9c8 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -345,10 +345,11 @@ 
 #define __NR_preadv		320
 #define __NR_pwritev		321
 #define __NR_rt_tgsigqueueinfo	322
+#define __NR_clock_adjtime	323
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls		323
+#define __NR_syscalls		324
 
 #define __NR__exit __NR_exit
 #define NR_syscalls	__NR_syscalls
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index b86feab..2771351 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -845,4 +845,5 @@  ia32_sys_call_table:
 	.quad sys_fanotify_init
 	.quad sys32_fanotify_mark
 	.quad sys_prlimit64		/* 340 */
+	.quad compat_sys_clock_adjtime
 ia32_syscall_end:
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index b766a5e..b6f73f1 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -346,10 +346,11 @@ 
 #define __NR_fanotify_init	338
 #define __NR_fanotify_mark	339
 #define __NR_prlimit64		340
+#define __NR_clock_adjtime	341
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 341
+#define NR_syscalls 342
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index 363e9b8..5ee3085 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -669,6 +669,8 @@  __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
 #define __NR_prlimit64				302
 __SYSCALL(__NR_prlimit64, sys_prlimit64)
+#define __NR_clock_adjtime			303
+__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index b35786d..68c7b9a 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -340,3 +340,4 @@  ENTRY(sys_call_table)
 	.long sys_fanotify_init
 	.long sys_fanotify_mark
 	.long sys_prlimit64		/* 340 */
+	.long sys_clock_adjtime
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 3e23844..08aa4da 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -4,6 +4,7 @@ 
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 
 union cpu_time_count {
 	cputime_t cpu;
@@ -67,10 +68,12 @@  struct k_itimer {
 };
 
 struct k_clock {
+	clockid_t id;
 	int res;		/* in nanoseconds */
 	int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
 	int (*clock_set) (const clockid_t which_clock, struct timespec * tp);
 	int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
+	int (*clock_adj) (const clockid_t which_clock, struct timex *tx);
 	int (*timer_create) (struct k_itimer *timer);
 	int (*nsleep) (const clockid_t which_clock, int flags,
 		       struct timespec *, struct timespec __user *);
@@ -84,7 +87,11 @@  struct k_clock {
 			   struct itimerspec * cur_setting);
 };
 
-void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock);
+/* Regsiter a posix clock with a "well known" clock id. */
+int register_posix_clock(const clockid_t id, struct k_clock *clock);
+
+/* Create a new posix clock with a dynamic clock id. */
+clockid_t create_posix_clock(struct k_clock *clock);
 
 /* error handlers for timer_create, nanosleep and settime */
 int do_posix_clock_nonanosleep(const clockid_t, int flags, struct timespec *,
@@ -97,6 +104,7 @@  int posix_timer_event(struct k_itimer *timr, int si_private);
 int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *ts);
 int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *ts);
 int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
+int posix_cpu_clock_adj(const clockid_t which_clock, struct timex *tx);
 int posix_cpu_timer_create(struct k_itimer *timer);
 int posix_cpu_nsleep(const clockid_t which_clock, int flags,
 		     struct timespec *rqtp, struct timespec __user *rmtp);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 6e5d197..0f4d57c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -313,6 +313,8 @@  asmlinkage long sys_clock_settime(clockid_t which_clock,
 				const struct timespec __user *tp);
 asmlinkage long sys_clock_gettime(clockid_t which_clock,
 				struct timespec __user *tp);
+asmlinkage long sys_clock_adjtime(clockid_t which_clock,
+				struct timex __user *tx);
 asmlinkage long sys_clock_getres(clockid_t which_clock,
 				struct timespec __user *tp);
 asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags,
diff --git a/include/linux/time.h b/include/linux/time.h
index 9f15ac7..914c48d 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -299,6 +299,8 @@  struct itimerval {
 #define CLOCKS_MASK			(CLOCK_REALTIME | CLOCK_MONOTONIC)
 #define CLOCKS_MONO			CLOCK_MONOTONIC
 
+#define CLOCK_INVALID			-1
+
 /*
  * The various flags for setting POSIX.1b interval timers:
  */
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 32d852f..82d4b24 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -73,7 +73,7 @@  struct timex {
 	long tolerance;		/* clock frequency tolerance (ppm)
 				 * (read only)
 				 */
-	struct timeval time;	/* (read only) */
+	struct timeval time;	/* (read only, except for ADJ_SETOFFSET) */
 	long tick;		/* (modified) usecs between clock ticks */
 
 	long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
@@ -101,6 +101,7 @@  struct timex {
 #define ADJ_ESTERROR		0x0008	/* estimated time error */
 #define ADJ_STATUS		0x0010	/* clock status */
 #define ADJ_TIMECONST		0x0020	/* pll time constant */
+#define ADJ_SETOFFSET		0x0040  /* add 'time' to current time */
 #define ADJ_TAI			0x0080	/* set TAI offset */
 #define ADJ_MICRO		0x1000	/* select microsecond resolution */
 #define ADJ_NANO		0x2000	/* select nanosecond resolution */
diff --git a/kernel/compat.c b/kernel/compat.c
index e167efc..f408ab5 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -52,6 +52,64 @@  static int compat_put_timeval(struct compat_timeval __user *o,
 		put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
 }
 
+static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
+{
+	memset(txc, 0, sizeof(struct timex));
+
+	if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
+			__get_user(txc->modes, &utp->modes) ||
+			__get_user(txc->offset, &utp->offset) ||
+			__get_user(txc->freq, &utp->freq) ||
+			__get_user(txc->maxerror, &utp->maxerror) ||
+			__get_user(txc->esterror, &utp->esterror) ||
+			__get_user(txc->status, &utp->status) ||
+			__get_user(txc->constant, &utp->constant) ||
+			__get_user(txc->precision, &utp->precision) ||
+			__get_user(txc->tolerance, &utp->tolerance) ||
+			__get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+			__get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+			__get_user(txc->tick, &utp->tick) ||
+			__get_user(txc->ppsfreq, &utp->ppsfreq) ||
+			__get_user(txc->jitter, &utp->jitter) ||
+			__get_user(txc->shift, &utp->shift) ||
+			__get_user(txc->stabil, &utp->stabil) ||
+			__get_user(txc->jitcnt, &utp->jitcnt) ||
+			__get_user(txc->calcnt, &utp->calcnt) ||
+			__get_user(txc->errcnt, &utp->errcnt) ||
+			__get_user(txc->stbcnt, &utp->stbcnt))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
+{
+	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
+			__put_user(txc->modes, &utp->modes) ||
+			__put_user(txc->offset, &utp->offset) ||
+			__put_user(txc->freq, &utp->freq) ||
+			__put_user(txc->maxerror, &utp->maxerror) ||
+			__put_user(txc->esterror, &utp->esterror) ||
+			__put_user(txc->status, &utp->status) ||
+			__put_user(txc->constant, &utp->constant) ||
+			__put_user(txc->precision, &utp->precision) ||
+			__put_user(txc->tolerance, &utp->tolerance) ||
+			__put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+			__put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+			__put_user(txc->tick, &utp->tick) ||
+			__put_user(txc->ppsfreq, &utp->ppsfreq) ||
+			__put_user(txc->jitter, &utp->jitter) ||
+			__put_user(txc->shift, &utp->shift) ||
+			__put_user(txc->stabil, &utp->stabil) ||
+			__put_user(txc->jitcnt, &utp->jitcnt) ||
+			__put_user(txc->calcnt, &utp->calcnt) ||
+			__put_user(txc->errcnt, &utp->errcnt) ||
+			__put_user(txc->stbcnt, &utp->stbcnt) ||
+			__put_user(txc->tai, &utp->tai))
+		return -EFAULT;
+	return 0;
+}
+
 asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
 		struct timezone __user *tz)
 {
@@ -617,6 +675,29 @@  long compat_sys_clock_gettime(clockid_t which_clock,
 	return err;
 }
 
+long compat_sys_clock_adjtime(clockid_t which_clock,
+		struct compat_timex __user *utp)
+{
+	struct timex txc;
+	mm_segment_t oldfs;
+	int err, ret;
+
+	err = compat_get_timex(&txc, utp);
+	if (err)
+		return err;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
+	set_fs(oldfs);
+
+	err = compat_put_timex(utp, &txc);
+	if (err)
+		return err;
+
+	return ret;
+}
+
 long compat_sys_clock_getres(clockid_t which_clock,
 		struct compat_timespec __user *tp)
 {
@@ -951,58 +1032,17 @@  asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
 {
 	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
+	int err, ret;
 
-	if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
-			__get_user(txc.modes, &utp->modes) ||
-			__get_user(txc.offset, &utp->offset) ||
-			__get_user(txc.freq, &utp->freq) ||
-			__get_user(txc.maxerror, &utp->maxerror) ||
-			__get_user(txc.esterror, &utp->esterror) ||
-			__get_user(txc.status, &utp->status) ||
-			__get_user(txc.constant, &utp->constant) ||
-			__get_user(txc.precision, &utp->precision) ||
-			__get_user(txc.tolerance, &utp->tolerance) ||
-			__get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-			__get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-			__get_user(txc.tick, &utp->tick) ||
-			__get_user(txc.ppsfreq, &utp->ppsfreq) ||
-			__get_user(txc.jitter, &utp->jitter) ||
-			__get_user(txc.shift, &utp->shift) ||
-			__get_user(txc.stabil, &utp->stabil) ||
-			__get_user(txc.jitcnt, &utp->jitcnt) ||
-			__get_user(txc.calcnt, &utp->calcnt) ||
-			__get_user(txc.errcnt, &utp->errcnt) ||
-			__get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
+	err = compat_get_timex(&txc, utp);
+	if (err)
+		return err;
 
 	ret = do_adjtimex(&txc);
 
-	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
-			__put_user(txc.modes, &utp->modes) ||
-			__put_user(txc.offset, &utp->offset) ||
-			__put_user(txc.freq, &utp->freq) ||
-			__put_user(txc.maxerror, &utp->maxerror) ||
-			__put_user(txc.esterror, &utp->esterror) ||
-			__put_user(txc.status, &utp->status) ||
-			__put_user(txc.constant, &utp->constant) ||
-			__put_user(txc.precision, &utp->precision) ||
-			__put_user(txc.tolerance, &utp->tolerance) ||
-			__put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-			__put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-			__put_user(txc.tick, &utp->tick) ||
-			__put_user(txc.ppsfreq, &utp->ppsfreq) ||
-			__put_user(txc.jitter, &utp->jitter) ||
-			__put_user(txc.shift, &utp->shift) ||
-			__put_user(txc.stabil, &utp->stabil) ||
-			__put_user(txc.jitcnt, &utp->jitcnt) ||
-			__put_user(txc.calcnt, &utp->calcnt) ||
-			__put_user(txc.errcnt, &utp->errcnt) ||
-			__put_user(txc.stbcnt, &utp->stbcnt) ||
-			__put_user(txc.tai, &utp->tai))
-		ret = -EFAULT;
+	err = compat_put_timex(utp, &txc);
+	if (err)
+		return err;
 
 	return ret;
 }
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 6842eeb..e1c2e7b 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -207,6 +207,10 @@  int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp)
 	return error;
 }
 
+int posix_cpu_clock_adj(const clockid_t which_clock, struct timex *tx)
+{
+	return -EOPNOTSUPP;
+}
 
 /*
  * Sample a per-thread clock for the given task.
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 9ca4973..67fba5c 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -132,6 +132,8 @@  static DEFINE_SPINLOCK(idr_lock);
  */
 
 static struct k_clock posix_clocks[MAX_CLOCKS];
+static DECLARE_BITMAP(clocks_map, MAX_CLOCKS);
+static DEFINE_MUTEX(clocks_mux); /* protects 'posix_clocks' and 'clocks_map' */
 
 /*
  * These ones are defined below.
@@ -197,6 +199,14 @@  static int common_timer_create(struct k_itimer *new_timer)
 	return 0;
 }
 
+static inline int common_clock_adj(const clockid_t which_clock, struct timex *t)
+{
+	if (CLOCK_REALTIME == which_clock)
+		return do_adjtimex(t);
+	else
+		return -EOPNOTSUPP;
+}
+
 static int no_timer_create(struct k_itimer *new_timer)
 {
 	return -EOPNOTSUPP;
@@ -476,18 +486,43 @@  static struct pid *good_sigevent(sigevent_t * event)
 	return task_pid(rtn);
 }
 
-void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock)
+int register_posix_clock(const clockid_t id, struct k_clock *clock)
 {
-	if ((unsigned) clock_id >= MAX_CLOCKS) {
-		printk("POSIX clock register failed for clock_id %d\n",
-		       clock_id);
-		return;
-	}
+	struct k_clock *kc;
+	int err = 0;
 
-	posix_clocks[clock_id] = *new_clock;
+	mutex_lock(&clocks_mux);
+	if (test_bit(id, clocks_map)) {
+		pr_err("clock_id %d already registered\n", id);
+		err = -EBUSY;
+		goto out;
+	}
+	kc = &posix_clocks[id];
+	*kc = *clock;
+	kc->id = id;
+	set_bit(id, clocks_map);
+out:
+	mutex_unlock(&clocks_mux);
+	return err;
 }
 EXPORT_SYMBOL_GPL(register_posix_clock);
 
+clockid_t create_posix_clock(struct k_clock *clock)
+{
+	clockid_t id;
+
+	mutex_lock(&clocks_mux);
+	id = find_first_zero_bit(clocks_map, MAX_CLOCKS);
+	mutex_unlock(&clocks_mux);
+
+	if (id < MAX_CLOCKS) {
+		register_posix_clock(id, clock);
+		return id;
+	}
+	return CLOCK_INVALID;
+}
+EXPORT_SYMBOL_GPL(create_posix_clock);
+
 static struct k_itimer * alloc_posix_timer(void)
 {
 	struct k_itimer *tmr;
@@ -969,6 +1004,15 @@  SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
 
 }
 
+SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
+		struct timex __user *, tx)
+{
+	if (invalid_clockid(which_clock))
+		return -EINVAL;
+
+	return CLOCK_DISPATCH(which_clock, clock_adj, (which_clock, tx));
+}
+
 SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
 		struct timespec __user *, tp)
 {