diff options
author | Trent Piepho <xyzzy@speakeasy.org> | 2006-03-30 13:53:32 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-04-02 03:56:01 -0400 |
commit | 5e85bd057f0cb29881e3d55d29f48bb55bd2f450 (patch) | |
tree | 7d1e582b25710d70487d1dc59e150b387a58c919 /drivers/media | |
parent | 2f03ee8e6bd7c6f40a1a0583662308e002d357da (diff) |
V4L/DVB (3672): Fix memory leak in dvr open
The dvr device could be opened multiple times simultaneously in O_RDONLY mode.
Each open after the first would allocate a new dvr buffer (1880 KB) and leak
the old buffer. The first close would de-allocate the dvr buffer and cause
all other open dvrs to stop working. This patch allows only a single O_RDONLY
open of the drv device, as per the API specification. Multiple O_WRONLY opens
are still allowed and don't appear to cause any problems.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb/dvb-core/dmxdev.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 09e96e9ddbdf..04578df3f249 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c | |||
@@ -141,12 +141,18 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) | |||
141 | } | 141 | } |
142 | 142 | ||
143 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | 143 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
144 | void *mem = vmalloc(DVR_BUFFER_SIZE); | 144 | void *mem; |
145 | if (!dvbdev->readers) { | ||
146 | mutex_unlock(&dmxdev->mutex); | ||
147 | return -EBUSY; | ||
148 | } | ||
149 | mem = vmalloc(DVR_BUFFER_SIZE); | ||
145 | if (!mem) { | 150 | if (!mem) { |
146 | mutex_unlock(&dmxdev->mutex); | 151 | mutex_unlock(&dmxdev->mutex); |
147 | return -ENOMEM; | 152 | return -ENOMEM; |
148 | } | 153 | } |
149 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); | 154 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); |
155 | dvbdev->readers--; | ||
150 | } | 156 | } |
151 | 157 | ||
152 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | 158 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
@@ -184,6 +190,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) | |||
184 | dmxdev->dvr_orig_fe); | 190 | dmxdev->dvr_orig_fe); |
185 | } | 191 | } |
186 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | 192 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
193 | dvbdev->readers++; | ||
187 | if (dmxdev->dvr_buffer.data) { | 194 | if (dmxdev->dvr_buffer.data) { |
188 | void *mem = dmxdev->dvr_buffer.data; | 195 | void *mem = dmxdev->dvr_buffer.data; |
189 | mb(); | 196 | mb(); |
@@ -1029,8 +1036,7 @@ static struct file_operations dvb_dvr_fops = { | |||
1029 | 1036 | ||
1030 | static struct dvb_device dvbdev_dvr = { | 1037 | static struct dvb_device dvbdev_dvr = { |
1031 | .priv = NULL, | 1038 | .priv = NULL, |
1032 | .users = 1, | 1039 | .readers = 1, |
1033 | .writers = 1, | ||
1034 | .fops = &dvb_dvr_fops | 1040 | .fops = &dvb_dvr_fops |
1035 | }; | 1041 | }; |
1036 | 1042 | ||