Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ppdev: convert to y2038 safe

The y2038 issue for ppdev is changes of timeval in the ioctl
(PPSETTIME and PPGETTIME). The size of struct timeval changes from
8bytes to 16bytes due to the changes of time_t. It lead to the
changes of the command of ioctl, e.g. for PPGETTIME, We have:

on 32-bit (old): 0x80087095
on 32-bit (new): 0x80107095
on 64-bit : 0x80107095

This patch define these two ioctl commands to support the 32bit
and 64bit time_t application at the same time. And, introduce
pp_set_timeout to remove some duplicated code.

Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Bamvor Jian Zhang and committed by
Greg Kroah-Hartman
3b9ab374 468623bb

+55 -20
+55 -20
drivers/char/ppdev.c
··· 98 98 #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) 99 99 100 100 static DEFINE_MUTEX(pp_do_mutex); 101 + 102 + /* define fixed sized ioctl cmd for y2038 migration */ 103 + #define PPGETTIME32 _IOR(PP_IOCTL, 0x95, s32[2]) 104 + #define PPSETTIME32 _IOW(PP_IOCTL, 0x96, s32[2]) 105 + #define PPGETTIME64 _IOR(PP_IOCTL, 0x95, s64[2]) 106 + #define PPSETTIME64 _IOW(PP_IOCTL, 0x96, s64[2]) 107 + 101 108 static inline void pp_enable_irq (struct pp_struct *pp) 102 109 { 103 110 struct parport *port = pp->pdev->port; ··· 329 322 return IEEE1284_PH_FWD_IDLE; 330 323 } 331 324 325 + static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec) 326 + { 327 + long to_jiffies; 328 + 329 + if ((tv_sec < 0) || (tv_usec < 0)) 330 + return -EINVAL; 331 + 332 + to_jiffies = usecs_to_jiffies(tv_usec); 333 + to_jiffies += tv_sec * HZ; 334 + if (to_jiffies <= 0) 335 + return -EINVAL; 336 + 337 + pdev->timeout = to_jiffies; 338 + return 0; 339 + } 340 + 332 341 static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 333 342 { 334 343 unsigned int minor = iminor(file_inode(file)); ··· 518 495 unsigned char reg; 519 496 unsigned char mask; 520 497 int mode; 498 + s32 time32[2]; 499 + s64 time64[2]; 500 + struct timespec64 ts; 521 501 int ret; 522 - struct timeval par_timeout; 523 - long to_jiffies; 524 502 525 503 case PPRSTATUS: 526 504 reg = parport_read_status (port); ··· 616 592 atomic_sub (ret, &pp->irqc); 617 593 return 0; 618 594 619 - case PPSETTIME: 620 - if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) { 595 + case PPSETTIME32: 596 + if (copy_from_user(time32, argp, sizeof(time32))) 621 597 return -EFAULT; 622 - } 623 - /* Convert to jiffies, place in pp->pdev->timeout */ 624 - if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) { 598 + 599 + return pp_set_timeout(pp->pdev, time32[0], time32[1]); 600 + 601 + case PPSETTIME64: 602 + if (copy_from_user(time64, argp, sizeof(time64))) 603 + return -EFAULT; 604 + 605 + return pp_set_timeout(pp->pdev, time64[0], time64[1]); 606 + 607 + case PPGETTIME32: 608 + jiffies_to_timespec64(pp->pdev->timeout, &ts); 609 + time32[0] = ts.tv_sec; 610 + time32[1] = ts.tv_nsec / NSEC_PER_USEC; 611 + if ((time32[0] < 0) || (time32[1] < 0)) 625 612 return -EINVAL; 626 - } 627 - to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); 628 - to_jiffies += par_timeout.tv_sec * (long)HZ; 629 - if (to_jiffies <= 0) { 630 - return -EINVAL; 631 - } 632 - pp->pdev->timeout = to_jiffies; 613 + 614 + if (copy_to_user(argp, time32, sizeof(time32))) 615 + return -EFAULT; 616 + 633 617 return 0; 634 618 635 - case PPGETTIME: 636 - to_jiffies = pp->pdev->timeout; 637 - memset(&par_timeout, 0, sizeof(par_timeout)); 638 - par_timeout.tv_sec = to_jiffies / HZ; 639 - par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ); 640 - if (copy_to_user (argp, &par_timeout, sizeof(struct timeval))) 619 + case PPGETTIME64: 620 + jiffies_to_timespec64(pp->pdev->timeout, &ts); 621 + time64[0] = ts.tv_sec; 622 + time64[1] = ts.tv_nsec / NSEC_PER_USEC; 623 + if ((time64[0] < 0) || (time64[1] < 0)) 624 + return -EINVAL; 625 + 626 + if (copy_to_user(argp, time64, sizeof(time64))) 641 627 return -EFAULT; 628 + 642 629 return 0; 643 630 644 631 default: