diff options
Diffstat (limited to 'sound/core/info.c')
-rw-r--r-- | sound/core/info.c | 75 |
1 files changed, 44 insertions, 31 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index d749a0d394a7..b70564ed8b37 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/time.h> | 23 | #include <linux/time.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/slab.h> | ||
25 | #include <linux/smp_lock.h> | 26 | #include <linux/smp_lock.h> |
26 | #include <linux/string.h> | 27 | #include <linux/string.h> |
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
@@ -163,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) | |||
163 | { | 164 | { |
164 | struct snd_info_private_data *data; | 165 | struct snd_info_private_data *data; |
165 | struct snd_info_entry *entry; | 166 | struct snd_info_entry *entry; |
166 | loff_t ret; | 167 | loff_t ret = -EINVAL, size; |
167 | 168 | ||
168 | data = file->private_data; | 169 | data = file->private_data; |
169 | entry = data->entry; | 170 | entry = data->entry; |
170 | lock_kernel(); | 171 | mutex_lock(&entry->access); |
171 | switch (entry->content) { | 172 | if (entry->content == SNDRV_INFO_CONTENT_DATA && |
172 | case SNDRV_INFO_CONTENT_TEXT: | 173 | entry->c.ops->llseek) { |
173 | switch (orig) { | 174 | offset = entry->c.ops->llseek(entry, |
174 | case SEEK_SET: | 175 | data->file_private_data, |
175 | file->f_pos = offset; | 176 | file, offset, orig); |
176 | ret = file->f_pos; | 177 | goto out; |
177 | goto out; | 178 | } |
178 | case SEEK_CUR: | 179 | if (entry->content == SNDRV_INFO_CONTENT_DATA) |
179 | file->f_pos += offset; | 180 | size = entry->size; |
180 | ret = file->f_pos; | 181 | else |
181 | goto out; | 182 | size = 0; |
182 | case SEEK_END: | 183 | switch (orig) { |
183 | default: | 184 | case SEEK_SET: |
184 | ret = -EINVAL; | ||
185 | goto out; | ||
186 | } | ||
187 | break; | 185 | break; |
188 | case SNDRV_INFO_CONTENT_DATA: | 186 | case SEEK_CUR: |
189 | if (entry->c.ops->llseek) { | 187 | offset += file->f_pos; |
190 | ret = entry->c.ops->llseek(entry, | 188 | break; |
191 | data->file_private_data, | 189 | case SEEK_END: |
192 | file, offset, orig); | 190 | if (!size) |
193 | goto out; | 191 | goto out; |
194 | } | 192 | offset += size; |
195 | break; | 193 | break; |
196 | } | 194 | default: |
197 | ret = -ENXIO; | 195 | goto out; |
198 | out: | 196 | } |
199 | unlock_kernel(); | 197 | if (offset < 0) |
198 | goto out; | ||
199 | if (size && offset > size) | ||
200 | offset = size; | ||
201 | file->f_pos = offset; | ||
202 | ret = offset; | ||
203 | out: | ||
204 | mutex_unlock(&entry->access); | ||
200 | return ret; | 205 | return ret; |
201 | } | 206 | } |
202 | 207 | ||
@@ -231,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, | |||
231 | return -EFAULT; | 236 | return -EFAULT; |
232 | break; | 237 | break; |
233 | case SNDRV_INFO_CONTENT_DATA: | 238 | case SNDRV_INFO_CONTENT_DATA: |
234 | if (entry->c.ops->read) | 239 | if (pos >= entry->size) |
240 | return 0; | ||
241 | if (entry->c.ops->read) { | ||
242 | size = entry->size - pos; | ||
243 | size = min(count, size); | ||
235 | size = entry->c.ops->read(entry, | 244 | size = entry->c.ops->read(entry, |
236 | data->file_private_data, | 245 | data->file_private_data, |
237 | file, buffer, count, pos); | 246 | file, buffer, size, pos); |
247 | } | ||
238 | break; | 248 | break; |
239 | } | 249 | } |
240 | if ((ssize_t) size > 0) | 250 | if ((ssize_t) size > 0) |
@@ -281,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
281 | size = count; | 291 | size = count; |
282 | break; | 292 | break; |
283 | case SNDRV_INFO_CONTENT_DATA: | 293 | case SNDRV_INFO_CONTENT_DATA: |
284 | if (entry->c.ops->write) | 294 | if (entry->c.ops->write && count > 0) { |
295 | size_t maxsize = entry->size - pos; | ||
296 | count = min(count, maxsize); | ||
285 | size = entry->c.ops->write(entry, | 297 | size = entry->c.ops->write(entry, |
286 | data->file_private_data, | 298 | data->file_private_data, |
287 | file, buffer, count, pos); | 299 | file, buffer, count, pos); |
300 | } | ||
288 | break; | 301 | break; |
289 | } | 302 | } |
290 | if ((ssize_t) size > 0) | 303 | if ((ssize_t) size > 0) |