Showing error 1809

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/media/video/ivtv/ivtv-queue.c
Line in file: 145
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

  1/*
  2    buffer queues.
  3    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
  4    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
  5    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
  6
  7    This program is free software; you can redistribute it and/or modify
  8    it under the terms of the GNU General Public License as published by
  9    the Free Software Foundation; either version 2 of the License, or
 10    (at your option) any later version.
 11
 12    This program is distributed in the hope that it will be useful,
 13    but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15    GNU General Public License for more details.
 16
 17    You should have received a copy of the GNU General Public License
 18    along with this program; if not, write to the Free Software
 19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 20 */
 21
 22#include "ivtv-driver.h"
 23#include "ivtv-queue.h"
 24
 25int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
 26{
 27        if (s->buf_size - buf->bytesused < copybytes)
 28                copybytes = s->buf_size - buf->bytesused;
 29        if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
 30                return -EFAULT;
 31        }
 32        buf->bytesused += copybytes;
 33        return copybytes;
 34}
 35
 36void ivtv_buf_swap(struct ivtv_buffer *buf)
 37{
 38        int i;
 39
 40        for (i = 0; i < buf->bytesused; i += 4)
 41                swab32s((u32 *)(buf->buf + i));
 42}
 43
 44void ivtv_queue_init(struct ivtv_queue *q)
 45{
 46        INIT_LIST_HEAD(&q->list);
 47        q->buffers = 0;
 48        q->length = 0;
 49        q->bytesused = 0;
 50}
 51
 52void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
 53{
 54        unsigned long flags;
 55
 56        /* clear the buffer if it is going to be enqueued to the free queue */
 57        if (q == &s->q_free) {
 58                buf->bytesused = 0;
 59                buf->readpos = 0;
 60                buf->b_flags = 0;
 61                buf->dma_xfer_cnt = 0;
 62        }
 63        spin_lock_irqsave(&s->qlock, flags);
 64        list_add_tail(&buf->list, &q->list);
 65        q->buffers++;
 66        q->length += s->buf_size;
 67        q->bytesused += buf->bytesused - buf->readpos;
 68        spin_unlock_irqrestore(&s->qlock, flags);
 69}
 70
 71struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
 72{
 73        struct ivtv_buffer *buf = NULL;
 74        unsigned long flags;
 75
 76        spin_lock_irqsave(&s->qlock, flags);
 77        if (!list_empty(&q->list)) {
 78                buf = list_entry(q->list.next, struct ivtv_buffer, list);
 79                list_del_init(q->list.next);
 80                q->buffers--;
 81                q->length -= s->buf_size;
 82                q->bytesused -= buf->bytesused - buf->readpos;
 83        }
 84        spin_unlock_irqrestore(&s->qlock, flags);
 85        return buf;
 86}
 87
 88static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
 89                struct ivtv_queue *to, int clear)
 90{
 91        struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
 92
 93        list_move_tail(from->list.next, &to->list);
 94        from->buffers--;
 95        from->length -= s->buf_size;
 96        from->bytesused -= buf->bytesused - buf->readpos;
 97        /* special handling for q_free */
 98        if (clear)
 99                buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
100        to->buffers++;
101        to->length += s->buf_size;
102        to->bytesused += buf->bytesused - buf->readpos;
103}
104
105/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
106   If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
107   If 'steal' != NULL, then buffers may also taken from that queue if
108   needed, but only if 'from' is the free queue.
109
110   The buffer is automatically cleared if it goes to the free queue. It is
111   also cleared if buffers need to be taken from the 'steal' queue and
112   the 'from' queue is the free queue.
113
114   When 'from' is q_free, then needed_bytes is compared to the total
115   available buffer length, otherwise needed_bytes is compared to the
116   bytesused value. For the 'steal' queue the total available buffer
117   length is always used.
118
119   -ENOMEM is returned if the buffers could not be obtained, 0 if all
120   buffers where obtained from the 'from' list and if non-zero then
121   the number of stolen buffers is returned. */
122int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
123                    struct ivtv_queue *to, int needed_bytes)
124{
125        unsigned long flags;
126        int rc = 0;
127        int from_free = from == &s->q_free;
128        int to_free = to == &s->q_free;
129        int bytes_available, bytes_steal;
130
131        spin_lock_irqsave(&s->qlock, flags);
132        if (needed_bytes == 0) {
133                from_free = 1;
134                needed_bytes = from->length;
135        }
136
137        bytes_available = from_free ? from->length : from->bytesused;
138        bytes_steal = (from_free && steal) ? steal->length : 0;
139
140        if (bytes_available + bytes_steal < needed_bytes) {
141                spin_unlock_irqrestore(&s->qlock, flags);
142                return -ENOMEM;
143        }
144        while (bytes_available < needed_bytes) {
145                struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
146                u16 dma_xfer_cnt = buf->dma_xfer_cnt;
147
148                /* move buffers from the tail of the 'steal' queue to the tail of the
149                   'from' queue. Always copy all the buffers with the same dma_xfer_cnt
150                   value, this ensures that you do not end up with partial frame data
151                   if one frame is stored in multiple buffers. */
152                while (dma_xfer_cnt == buf->dma_xfer_cnt) {
153                        list_move_tail(steal->list.prev, &from->list);
154                        rc++;
155                        steal->buffers--;
156                        steal->length -= s->buf_size;
157                        steal->bytesused -= buf->bytesused - buf->readpos;
158                        buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
159                        from->buffers++;
160                        from->length += s->buf_size;
161                        bytes_available += s->buf_size;
162                        if (list_empty(&steal->list))
163                                break;
164                        buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
165                }
166        }
167        if (from_free) {
168                u32 old_length = to->length;
169
170                while (to->length - old_length < needed_bytes) {
171                        ivtv_queue_move_buf(s, from, to, 1);
172                }
173        }
174        else {
175                u32 old_bytesused = to->bytesused;
176
177                while (to->bytesused - old_bytesused < needed_bytes) {
178                        ivtv_queue_move_buf(s, from, to, to_free);
179                }
180        }
181        spin_unlock_irqrestore(&s->qlock, flags);
182        return rc;
183}
184
185void ivtv_flush_queues(struct ivtv_stream *s)
186{
187        ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
188        ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
189        ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
190        ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
191}
192
193int ivtv_stream_alloc(struct ivtv_stream *s)
194{
195        struct ivtv *itv = s->itv;
196        int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
197        int i;
198
199        if (s->buffers == 0)
200                return 0;
201
202        IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
203                s->dma != PCI_DMA_NONE ? "DMA " : "",
204                s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
205
206        s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
207        if (s->sg_pending == NULL) {
208                IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
209                return -ENOMEM;
210        }
211        s->sg_pending_size = 0;
212
213        s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
214        if (s->sg_processing == NULL) {
215                IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
216                kfree(s->sg_pending);
217                s->sg_pending = NULL;
218                return -ENOMEM;
219        }
220        s->sg_processing_size = 0;
221
222        s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
223                                        GFP_KERNEL|__GFP_NOWARN);
224        if (s->sg_dma == NULL) {
225                IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
226                kfree(s->sg_pending);
227                s->sg_pending = NULL;
228                kfree(s->sg_processing);
229                s->sg_processing = NULL;
230                return -ENOMEM;
231        }
232        if (ivtv_might_use_dma(s)) {
233                s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
234                ivtv_stream_sync_for_cpu(s);
235        }
236
237        /* allocate stream buffers. Initially all buffers are in q_free. */
238        for (i = 0; i < s->buffers; i++) {
239                struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
240                                                GFP_KERNEL|__GFP_NOWARN);
241
242                if (buf == NULL)
243                        break;
244                buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
245                if (buf->buf == NULL) {
246                        kfree(buf);
247                        break;
248                }
249                INIT_LIST_HEAD(&buf->list);
250                if (ivtv_might_use_dma(s)) {
251                        buf->dma_handle = pci_map_single(s->itv->dev,
252                                buf->buf, s->buf_size + 256, s->dma);
253                        ivtv_buf_sync_for_cpu(s, buf);
254                }
255                ivtv_enqueue(s, buf, &s->q_free);
256        }
257        if (i == s->buffers)
258                return 0;
259        IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
260        ivtv_stream_free(s);
261        return -ENOMEM;
262}
263
264void ivtv_stream_free(struct ivtv_stream *s)
265{
266        struct ivtv_buffer *buf;
267
268        /* move all buffers to q_free */
269        ivtv_flush_queues(s);
270
271        /* empty q_free */
272        while ((buf = ivtv_dequeue(s, &s->q_free))) {
273                if (ivtv_might_use_dma(s))
274                        pci_unmap_single(s->itv->dev, buf->dma_handle,
275                                s->buf_size + 256, s->dma);
276                kfree(buf->buf);
277                kfree(buf);
278        }
279
280        /* Free SG Array/Lists */
281        if (s->sg_dma != NULL) {
282                if (s->sg_handle != IVTV_DMA_UNMAPPED) {
283                        pci_unmap_single(s->itv->dev, s->sg_handle,
284                                 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
285                        s->sg_handle = IVTV_DMA_UNMAPPED;
286                }
287                kfree(s->sg_pending);
288                kfree(s->sg_processing);
289                kfree(s->sg_dma);
290                s->sg_pending = NULL;
291                s->sg_processing = NULL;
292                s->sg_dma = NULL;
293                s->sg_pending_size = 0;
294                s->sg_processing_size = 0;
295        }
296}