diff options
| -rw-r--r-- | drivers/gpio/gpiolib.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 20e09b7c2de3..93ed0e00c578 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
| 22 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
| 23 | #include <linux/anon_inodes.h> | 23 | #include <linux/anon_inodes.h> |
| 24 | #include <linux/file.h> | ||
| 24 | #include <linux/kfifo.h> | 25 | #include <linux/kfifo.h> |
| 25 | #include <linux/poll.h> | 26 | #include <linux/poll.h> |
| 26 | #include <linux/timekeeping.h> | 27 | #include <linux/timekeeping.h> |
| @@ -423,6 +424,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) | |||
| 423 | { | 424 | { |
| 424 | struct gpiohandle_request handlereq; | 425 | struct gpiohandle_request handlereq; |
| 425 | struct linehandle_state *lh; | 426 | struct linehandle_state *lh; |
| 427 | struct file *file; | ||
| 426 | int fd, i, ret; | 428 | int fd, i, ret; |
| 427 | 429 | ||
| 428 | if (copy_from_user(&handlereq, ip, sizeof(handlereq))) | 430 | if (copy_from_user(&handlereq, ip, sizeof(handlereq))) |
| @@ -499,26 +501,41 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) | |||
| 499 | i--; | 501 | i--; |
| 500 | lh->numdescs = handlereq.lines; | 502 | lh->numdescs = handlereq.lines; |
| 501 | 503 | ||
| 502 | fd = anon_inode_getfd("gpio-linehandle", | 504 | fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); |
| 503 | &linehandle_fileops, | ||
| 504 | lh, | ||
| 505 | O_RDONLY | O_CLOEXEC); | ||
| 506 | if (fd < 0) { | 505 | if (fd < 0) { |
| 507 | ret = fd; | 506 | ret = fd; |
| 508 | goto out_free_descs; | 507 | goto out_free_descs; |
| 509 | } | 508 | } |
| 510 | 509 | ||
| 510 | file = anon_inode_getfile("gpio-linehandle", | ||
| 511 | &linehandle_fileops, | ||
| 512 | lh, | ||
| 513 | O_RDONLY | O_CLOEXEC); | ||
| 514 | if (IS_ERR(file)) { | ||
| 515 | ret = PTR_ERR(file); | ||
| 516 | goto out_put_unused_fd; | ||
| 517 | } | ||
| 518 | |||
| 511 | handlereq.fd = fd; | 519 | handlereq.fd = fd; |
| 512 | if (copy_to_user(ip, &handlereq, sizeof(handlereq))) { | 520 | if (copy_to_user(ip, &handlereq, sizeof(handlereq))) { |
| 513 | ret = -EFAULT; | 521 | /* |
| 514 | goto out_free_descs; | 522 | * fput() will trigger the release() callback, so do not go onto |
| 523 | * the regular error cleanup path here. | ||
| 524 | */ | ||
| 525 | fput(file); | ||
| 526 | put_unused_fd(fd); | ||
| 527 | return -EFAULT; | ||
| 515 | } | 528 | } |
| 516 | 529 | ||
| 530 | fd_install(fd, file); | ||
| 531 | |||
| 517 | dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n", | 532 | dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n", |
| 518 | lh->numdescs); | 533 | lh->numdescs); |
| 519 | 534 | ||
| 520 | return 0; | 535 | return 0; |
| 521 | 536 | ||
| 537 | out_put_unused_fd: | ||
| 538 | put_unused_fd(fd); | ||
| 522 | out_free_descs: | 539 | out_free_descs: |
| 523 | for (; i >= 0; i--) | 540 | for (; i >= 0; i--) |
| 524 | gpiod_free(lh->descs[i]); | 541 | gpiod_free(lh->descs[i]); |
| @@ -721,6 +738,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) | |||
| 721 | struct gpioevent_request eventreq; | 738 | struct gpioevent_request eventreq; |
| 722 | struct lineevent_state *le; | 739 | struct lineevent_state *le; |
| 723 | struct gpio_desc *desc; | 740 | struct gpio_desc *desc; |
| 741 | struct file *file; | ||
| 724 | u32 offset; | 742 | u32 offset; |
| 725 | u32 lflags; | 743 | u32 lflags; |
| 726 | u32 eflags; | 744 | u32 eflags; |
| @@ -815,23 +833,38 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) | |||
| 815 | if (ret) | 833 | if (ret) |
| 816 | goto out_free_desc; | 834 | goto out_free_desc; |
| 817 | 835 | ||
| 818 | fd = anon_inode_getfd("gpio-event", | 836 | fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); |
| 819 | &lineevent_fileops, | ||
| 820 | le, | ||
| 821 | O_RDONLY | O_CLOEXEC); | ||
| 822 | if (fd < 0) { | 837 | if (fd < 0) { |
| 823 | ret = fd; | 838 | ret = fd; |
| 824 | goto out_free_irq; | 839 | goto out_free_irq; |
| 825 | } | 840 | } |
| 826 | 841 | ||
| 842 | file = anon_inode_getfile("gpio-event", | ||
| 843 | &lineevent_fileops, | ||
| 844 | le, | ||
| 845 | O_RDONLY | O_CLOEXEC); | ||
| 846 | if (IS_ERR(file)) { | ||
| 847 | ret = PTR_ERR(file); | ||
| 848 | goto out_put_unused_fd; | ||
| 849 | } | ||
| 850 | |||
| 827 | eventreq.fd = fd; | 851 | eventreq.fd = fd; |
| 828 | if (copy_to_user(ip, &eventreq, sizeof(eventreq))) { | 852 | if (copy_to_user(ip, &eventreq, sizeof(eventreq))) { |
| 829 | ret = -EFAULT; | 853 | /* |
| 830 | goto out_free_irq; | 854 | * fput() will trigger the release() callback, so do not go onto |
| 855 | * the regular error cleanup path here. | ||
| 856 | */ | ||
| 857 | fput(file); | ||
| 858 | put_unused_fd(fd); | ||
| 859 | return -EFAULT; | ||
| 831 | } | 860 | } |
| 832 | 861 | ||
| 862 | fd_install(fd, file); | ||
| 863 | |||
| 833 | return 0; | 864 | return 0; |
| 834 | 865 | ||
| 866 | out_put_unused_fd: | ||
| 867 | put_unused_fd(fd); | ||
| 835 | out_free_irq: | 868 | out_free_irq: |
| 836 | free_irq(le->irq, le); | 869 | free_irq(le->irq, le); |
| 837 | out_free_desc: | 870 | out_free_desc: |
