aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Khoroshilov <khoroshilov@ispras.ru>2013-05-07 16:57:08 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-05-21 07:23:31 -0400
commit5255e4d9dfe2e33a5d68c54f6d1bee28fc5edd66 (patch)
tree752d04c450af3b822dc65df7eaa1068586e4c51d
parent88107675fba0b83d45744e9f2414dfea21686f87 (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.c24
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