Showing error 1467

User: Jiri Slaby
Error type: Leaving function in locked state
Error type description: Some lock is not unlocked on all paths of a function, so it is leaked
File location: net/core/gen_stats.c
Line in file: 72
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2012-05-21 20:30:05 UTC


Source:

  1/*
  2 * net/core/gen_stats.c
  3 *
  4 *             This program is free software; you can redistribute it and/or
  5 *             modify it under the terms of the GNU General Public License
  6 *             as published by the Free Software Foundation; either version
  7 *             2 of the License, or (at your option) any later version.
  8 *
  9 * Authors:  Thomas Graf <tgraf@suug.ch>
 10 *           Jamal Hadi Salim
 11 *           Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
 12 *
 13 * See Documentation/networking/gen_stats.txt
 14 */
 15
 16#include <linux/types.h>
 17#include <linux/kernel.h>
 18#include <linux/module.h>
 19#include <linux/interrupt.h>
 20#include <linux/socket.h>
 21#include <linux/rtnetlink.h>
 22#include <linux/gen_stats.h>
 23#include <net/netlink.h>
 24#include <net/gen_stats.h>
 25
 26
 27static inline int
 28gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
 29{
 30        NLA_PUT(d->skb, type, size, buf);
 31        return 0;
 32
 33nla_put_failure:
 34        spin_unlock_bh(d->lock);
 35        return -1;
 36}
 37
 38/**
 39 * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
 40 * @skb: socket buffer to put statistics TLVs into
 41 * @type: TLV type for top level statistic TLV
 42 * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV
 43 * @xstats_type: TLV type for backward compatibility xstats TLV
 44 * @lock: statistics lock
 45 * @d: dumping handle
 46 *
 47 * Initializes the dumping handle, grabs the statistic lock and appends
 48 * an empty TLV header to the socket buffer for use a container for all
 49 * other statistic TLVS.
 50 *
 51 * The dumping handle is marked to be in backward compatibility mode telling
 52 * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats.
 53 *
 54 * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
 55 */
 56int
 57gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
 58        int xstats_type, spinlock_t *lock, struct gnet_dump *d)
 59        __acquires(lock)
 60{
 61        memset(d, 0, sizeof(*d));
 62
 63        spin_lock_bh(lock);
 64        d->lock = lock;
 65        if (type)
 66                d->tail = (struct nlattr *)skb_tail_pointer(skb);
 67        d->skb = skb;
 68        d->compat_tc_stats = tc_stats_type;
 69        d->compat_xstats = xstats_type;
 70
 71        if (d->tail)
 72                return gnet_stats_copy(d, type, NULL, 0);
 73
 74        return 0;
 75}
 76
 77/**
 78 * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
 79 * @skb: socket buffer to put statistics TLVs into
 80 * @type: TLV type for top level statistic TLV
 81 * @lock: statistics lock
 82 * @d: dumping handle
 83 *
 84 * Initializes the dumping handle, grabs the statistic lock and appends
 85 * an empty TLV header to the socket buffer for use a container for all
 86 * other statistic TLVS.
 87 *
 88 * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
 89 */
 90int
 91gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
 92        struct gnet_dump *d)
 93{
 94        return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
 95}
 96
 97/**
 98 * gnet_stats_copy_basic - copy basic statistics into statistic TLV
 99 * @d: dumping handle
100 * @b: basic statistics
101 *
102 * Appends the basic statistics to the top level TLV created by
103 * gnet_stats_start_copy().
104 *
105 * Returns 0 on success or -1 with the statistic lock released
106 * if the room in the socket buffer was not sufficient.
107 */
108int
109gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic *b)
110{
111        if (d->compat_tc_stats) {
112                d->tc_stats.bytes = b->bytes;
113                d->tc_stats.packets = b->packets;
114        }
115
116        if (d->tail)
117                return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
118
119        return 0;
120}
121
122/**
123 * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
124 * @d: dumping handle
125 * @r: rate estimator statistics
126 *
127 * Appends the rate estimator statistics to the top level TLV created by
128 * gnet_stats_start_copy().
129 *
130 * Returns 0 on success or -1 with the statistic lock released
131 * if the room in the socket buffer was not sufficient.
132 */
133int
134gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
135{
136        if (d->compat_tc_stats) {
137                d->tc_stats.bps = r->bps;
138                d->tc_stats.pps = r->pps;
139        }
140
141        if (d->tail)
142                return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));
143
144        return 0;
145}
146
147/**
148 * gnet_stats_copy_queue - copy queue statistics into statistics TLV
149 * @d: dumping handle
150 * @q: queue statistics
151 *
152 * Appends the queue statistics to the top level TLV created by
153 * gnet_stats_start_copy().
154 *
155 * Returns 0 on success or -1 with the statistic lock released
156 * if the room in the socket buffer was not sufficient.
157 */
158int
159gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)
160{
161        if (d->compat_tc_stats) {
162                d->tc_stats.drops = q->drops;
163                d->tc_stats.qlen = q->qlen;
164                d->tc_stats.backlog = q->backlog;
165                d->tc_stats.overlimits = q->overlimits;
166        }
167
168        if (d->tail)
169                return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
170
171        return 0;
172}
173
174/**
175 * gnet_stats_copy_app - copy application specific statistics into statistics TLV
176 * @d: dumping handle
177 * @st: application specific statistics data
178 * @len: length of data
179 *
180 * Appends the application sepecific statistics to the top level TLV created by
181 * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping
182 * handle is in backward compatibility mode.
183 *
184 * Returns 0 on success or -1 with the statistic lock released
185 * if the room in the socket buffer was not sufficient.
186 */
187int
188gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
189{
190        if (d->compat_xstats) {
191                d->xstats = st;
192                d->xstats_len = len;
193        }
194
195        if (d->tail)
196                return gnet_stats_copy(d, TCA_STATS_APP, st, len);
197
198        return 0;
199}
200
201/**
202 * gnet_stats_finish_copy - finish dumping procedure
203 * @d: dumping handle
204 *
205 * Corrects the length of the top level TLV to include all TLVs added
206 * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs
207 * if gnet_stats_start_copy_compat() was used and releases the statistics
208 * lock.
209 *
210 * Returns 0 on success or -1 with the statistic lock released
211 * if the room in the socket buffer was not sufficient.
212 */
213int
214gnet_stats_finish_copy(struct gnet_dump *d)
215{
216        if (d->tail)
217                d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;
218
219        if (d->compat_tc_stats)
220                if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
221                        sizeof(d->tc_stats)) < 0)
222                        return -1;
223
224        if (d->compat_xstats && d->xstats) {
225                if (gnet_stats_copy(d, d->compat_xstats, d->xstats,
226                        d->xstats_len) < 0)
227                        return -1;
228        }
229
230        spin_unlock_bh(d->lock);
231        return 0;
232}
233
234
235EXPORT_SYMBOL(gnet_stats_start_copy);
236EXPORT_SYMBOL(gnet_stats_start_copy_compat);
237EXPORT_SYMBOL(gnet_stats_copy_basic);
238EXPORT_SYMBOL(gnet_stats_copy_rate_est);
239EXPORT_SYMBOL(gnet_stats_copy_queue);
240EXPORT_SYMBOL(gnet_stats_copy_app);
241EXPORT_SYMBOL(gnet_stats_finish_copy);