diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2013-05-07 16:57:08 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-05-21 07:23:31 -0400 |
commit | 5255e4d9dfe2e33a5d68c54f6d1bee28fc5edd66 (patch) | |
tree | 752d04c450af3b822dc65df7eaa1068586e4c51d | |
parent | 88107675fba0b83d45744e9f2414dfea21686f87 (diff) |
[media] wl128x: do not call copy_to_user() while holding spinlocks
copy_to_user() must not be called with spinlocks held, but it is in
fmc_transfer_rds_from_internal_buff().
The patch copies data to tmpbuf, releases spinlock and then passes it to userspace.
By the way there is a small unification: replace a couple of hardcoded constants by a macro.
Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/radio/wl128x/fmdrv_common.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index a002234ed5de..253f307f0b37 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c | |||
@@ -715,7 +715,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) | |||
715 | struct fm_rdsdata_format rds_fmt; | 715 | struct fm_rdsdata_format rds_fmt; |
716 | struct fm_rds *rds = &fmdev->rx.rds; | 716 | struct fm_rds *rds = &fmdev->rx.rds; |
717 | unsigned long group_idx, flags; | 717 | unsigned long group_idx, flags; |
718 | u8 *rds_data, meta_data, tmpbuf[3]; | 718 | u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE]; |
719 | u8 type, blk_idx; | 719 | u8 type, blk_idx; |
720 | u16 cur_picode; | 720 | u16 cur_picode; |
721 | u32 rds_len; | 721 | u32 rds_len; |
@@ -1073,6 +1073,7 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, | |||
1073 | u8 __user *buf, size_t count) | 1073 | u8 __user *buf, size_t count) |
1074 | { | 1074 | { |
1075 | u32 block_count; | 1075 | u32 block_count; |
1076 | u8 tmpbuf[FM_RDS_BLK_SIZE]; | ||
1076 | unsigned long flags; | 1077 | unsigned long flags; |
1077 | int ret; | 1078 | int ret; |
1078 | 1079 | ||
@@ -1087,29 +1088,32 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, | |||
1087 | } | 1088 | } |
1088 | 1089 | ||
1089 | /* Calculate block count from byte count */ | 1090 | /* Calculate block count from byte count */ |
1090 | count /= 3; | 1091 | count /= FM_RDS_BLK_SIZE; |
1091 | block_count = 0; | 1092 | block_count = 0; |
1092 | ret = 0; | 1093 | ret = 0; |
1093 | 1094 | ||
1094 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); | ||
1095 | |||
1096 | while (block_count < count) { | 1095 | while (block_count < count) { |
1097 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) | 1096 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); |
1098 | break; | ||
1099 | 1097 | ||
1100 | if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], | 1098 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { |
1101 | FM_RDS_BLK_SIZE)) | 1099 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); |
1102 | break; | 1100 | break; |
1103 | 1101 | } | |
1102 | memcpy(tmpbuf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], | ||
1103 | FM_RDS_BLK_SIZE); | ||
1104 | fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; | 1104 | fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; |
1105 | if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) | 1105 | if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) |
1106 | fmdev->rx.rds.rd_idx = 0; | 1106 | fmdev->rx.rds.rd_idx = 0; |
1107 | 1107 | ||
1108 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); | ||
1109 | |||
1110 | if (copy_to_user(buf, tmpbuf, FM_RDS_BLK_SIZE)) | ||
1111 | break; | ||
1112 | |||
1108 | block_count++; | 1113 | block_count++; |
1109 | buf += FM_RDS_BLK_SIZE; | 1114 | buf += FM_RDS_BLK_SIZE; |
1110 | ret += FM_RDS_BLK_SIZE; | 1115 | ret += FM_RDS_BLK_SIZE; |
1111 | } | 1116 | } |
1112 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); | ||
1113 | return ret; | 1117 | return ret; |
1114 | } | 1118 | } |
1115 | 1119 | ||