Hi, Arnd

On 07/17/2015 08:59 PM, Arnd Bergmann wrote:
> On Friday 17 July 2015 15:21:07 Bamvor Zhang Jian wrote:
>> diff --git a/include/sound/timer.h b/include/sound/timer.h
>> index 7990469..2cfee32 100644
>> --- a/include/sound/timer.h
>> +++ b/include/sound/timer.h
>> @@ -120,6 +120,12 @@ struct snd_timer_instance {
>>      struct snd_timer_instance *master;
>>  };
>>  
>> +struct snd_timer_tread {
>> +    int event;
>> +    struct timespec64 tstamp;
>> +    unsigned int val;
>> +};
>> +
>>  /*
>>   *  Registering
>>   */
>> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
>> index a45be6b..f7e3793 100644
>> --- a/include/uapi/sound/asound.h
>> +++ b/include/uapi/sound/asound.h
>> @@ -29,6 +29,9 @@
>>  #include <stdlib.h>
>>  #endif
>>  
>> +#ifndef CONFIG_COMPAT_TIME
>> +# define __kernel_timespec timespec
>> +#endif
> 
> CONFIG_COMPAT_TIME cannot be used in a uapi header: whether user space uses
> a 64-bit or 32-bit time_t is independent of what gets implemented in the
> kernel.
Oh, sorry for doing this again.
Originally, I want to follow your approach in "include/linux/time64.h" in
patch[1] in order to work with(for y2038 safe) and without(for keeping abi
unchaged) your patch[1].
On the other hand, when I write this commit, I found that there are some headers
include the <linux/time.h>(most them are drivers):
include/uapi/linux/videodev2.h, include/uapi/linux/input.h,
include/uapi/linux/timex.h, include/uapi/linux/elfcore.h,
include/uapi/linux/resource.h, include/uapi/linux/dvb/dmx.h,
include/uapi/linux/dvb/video.h,
include/uapi/linux/coda.h. CONFIG_COMPAT_TIME is used indirectly in uapi
files. Do we need to fix these issues?
>>   *  protocol version
>>   */
>> @@ -739,7 +742,7 @@ struct snd_timer_params {
>>  };
>>  
>>  struct snd_timer_status {
>> -    struct timespec tstamp;         /* Timestamp - last update */
>> +    struct __kernel_timespec tstamp;/* Timestamp - last update */
>>      unsigned int resolution;        /* current period resolution in ns */
>>      unsigned int lost;              /* counter of master tick lost */
>>      unsigned int overrun;           /* count of read queue overruns */
>> @@ -787,9 +790,9 @@ enum {
>>      SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
>>  };
>>  
>> -struct snd_timer_tread {
>> +struct __kernel_snd_timer_tread {
>>      int event;
>> -    struct timespec tstamp;
>> +    struct __kernel_timespec tstamp;
>>      unsigned int val;
>>  };
> 
> Also, __kernel_timespec is defined to be always 64-bit wide. This means
> if we do this change (assuming we drop the #define above), then user space
> will always see the new definition of this structure, and programs
> compiled against the latest header will no longer work on older kernels.
> 
> Is this what you had in mind? 
Yes. It was what in my head. But I do not whether it ought to be.
> 
> We could decide to do it like this, and we have historically done changes
> to the ioctl interface this way, but I'm not sure if we want to do it
> for all ioctls.
> 
> The alternative is to leave the 'timespec' visible here for user space,
> so user programs will see either the old or the new definition of struct
> depending on their timespec definition, and only programs built with
> 64-bit time_t will require new kernels.
Do you mean we leave snd_timer_tread unchanged and introduce a new struct?
(assuming we drop the #define above).
struct snd_timer_tread64 {
    int event;
    struct timespec tstamp;
    struct __kernel_timespec tstamp;
    unsigned int val;
};

#if BITS_PER_TIME_T == BITS_PER_LONG
#define SNDRV_TIMER_IOCTL_TREAD         _IOW('T', 0x02, int)
#else
#define SNDRV_TIMER_IOCTL_TREAD64       _IOW('T', 0x15, int)
#endif

snd_timer_tread64 is used by SNDRV_TIMER_IOCTL_TREAD64.

IIUC, we should define SNDRV_TIMER_IOCTL_TREAD64 instead keep the same name for
differenct ioctl, otherwise it is hard to support the old and new application
binary in new kernel.
>>  
>> +void snd_timer_notify(struct snd_timer *timer, int event, struct timespec 
>> *tstamp)
>> +{
>> +    struct timespec64 tstamp64;
>> +
>> +    tstamp64.tv_sec = tstamp->tv_sec;
>> +    tstamp64.tv_nsec = tstamp->tv_nsec;
>> +    snd_timer_notify64(timer, event, &tstamp64);
>> +}
> 
> This works, but I'd leave it up to Mark if he'd prefer to do the conversion
> bit by bit and change over all users of snd_timer_notify to use
> snd_timer_notify64, or to move them all at once and leave the function
> name unchanged.
Yes, understand. I want to keep the function name unchanged too. I guess I will
do it when pcm part of y2038 patches is ready. Otherwise, the sound subsystem
is broken.
> 
> I can see six callers of snd_timer_notify, but they are all in the same
> file, so I'd expect it to be possible to convert them all together,
> e.g. by adding a patch that changes the prototype in all these
> callers after changing the ccallback prototype.
Got you.
>> @@ -1702,7 +1712,8 @@ static int snd_timer_user_status(struct file *file,
>>      if (!tu->timeri)
>>              return -EBADFD;
>>      memset(&status, 0, sizeof(status));
>> -    status.tstamp = tu->tstamp;
>> +    status.tstamp.tv_sec = tu->tstamp.tv_sec;
>> +    status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
>>      status.resolution = snd_timer_resolution(tu->timeri);
>>      status.lost = tu->timeri->lost;
>>      status.overrun = tu->overrun;
> 
> With the change to the structure definition, this will now only handle
> the new structure size on patched kernels, but not work with old
> user space on native 32-bit kernels any more.
> 
> Your patch 2 fixes the case of handling both old compat 32-bit user space 
> on 64-bit kernels as well as new compat 32-bit user space with 64-bit
> time_t, but I think you are missing the case of handling old 32-bit
> user space.
> 
> Note that we cannot use compat_ioctl() for native 32-bit kernels, so
> snd_timer_user_ioctl will now have to be changed to handle both cases.
Oh, I miss it, I will try to add it in my next version.
>> @@ -1843,9 +1854,12 @@ static ssize_t snd_timer_user_read(struct file *file, 
>> char __user *buffer,
>>      struct snd_timer_user *tu;
>>      long result = 0, unit;
>>      int err = 0;
>> +    struct __kernel_snd_timer_tread kttr;
>> +    struct snd_timer_tread *ttrp;
>>  
>>      tu = file->private_data;
>> -    unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct 
>> snd_timer_read);
>> +    unit = tu->tread ? sizeof(struct __kernel_snd_timer_tread) :
>> +            sizeof(struct snd_timer_read);
>>      spin_lock_irq(&tu->qlock);
>>      while ((long)count - result >= unit) {
>>              while (!tu->qused) {
> 
> Now this is the part that gets really tricky: Instead of two cases
> (read and tread), we now have to handle three cases. Any user space
> that is compiled with 64-bit time_t needs to get the new structure,
> while old user space needs to get the old structure.
> 
> It looks like we already get this wrong for existing compat user
> space: running a 32-bit program on a 64-bit kernel will currently
> get the 64-bit version of struct snd_timer_tread and misinterpret
> that. We can probably fix both issues at the same time after
> introducing turning the tread flag into a three-way enum (or something
> along that lines).
It seems that the current tread flag select the read or tread. How about
choose the following you mentioned to deal with it?
if (tu->tread)
    if (BITS_PER_TIME_T == BITS_PER_LONG)
        unit = sizeof(struct snd_timer_tread);
    else
        unit = sizeof(struct snd_timer_tread64);
else
    unit = sizeof(struct snd_timer_read);

> I would recommend separating the tread changes from the user_status
> changes, as both of them are getting more complex now.
Ok.
> 
>       Arnd
> 

regards

bamvor
[1] 
http://git.kernel.org/cgit/linux/kernel/git/arnd/playground.git/commit/?h=y2038-syscalls&id=9005d4f4a44fc56bd0a1fe7c08e8e3f13eb75de7
_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038

Reply via email to