Showing error 1453

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/8021q/vlanproc.c
Line in file: 213
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2012-05-21 20:30:05 UTC


Source:

  1/******************************************************************************
  2 * vlanproc.c        VLAN Module. /proc filesystem interface.
  3 *
  4 *                This module is completely hardware-independent and provides
  5 *                access to the router using Linux /proc filesystem.
  6 *
  7 * Author:        Ben Greear, <greearb@candelatech.com> coppied from wanproc.c
  8 *               by: Gene Kozin        <genek@compuserve.com>
  9 *
 10 * Copyright:        (c) 1998 Ben Greear
 11 *
 12 *                This program is free software; you can redistribute it and/or
 13 *                modify it under the terms of the GNU General Public License
 14 *                as published by the Free Software Foundation; either version
 15 *                2 of the License, or (at your option) any later version.
 16 * ============================================================================
 17 * Jan 20, 1998        Ben Greear     Initial Version
 18 *****************************************************************************/
 19
 20#include <linux/module.h>
 21#include <linux/errno.h>
 22#include <linux/kernel.h>
 23#include <linux/string.h>
 24#include <linux/proc_fs.h>
 25#include <linux/seq_file.h>
 26#include <linux/fs.h>
 27#include <linux/netdevice.h>
 28#include <linux/if_vlan.h>
 29#include <net/net_namespace.h>
 30#include <net/netns/generic.h>
 31#include "vlanproc.h"
 32#include "vlan.h"
 33
 34/****** Function Prototypes *************************************************/
 35
 36/* Methods for preparing data for reading proc entries */
 37static int vlan_seq_show(struct seq_file *seq, void *v);
 38static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
 39static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 40static void vlan_seq_stop(struct seq_file *seq, void *);
 41static int vlandev_seq_show(struct seq_file *seq, void *v);
 42
 43/*
 44 *        Global Data
 45 */
 46
 47
 48/*
 49 *        Names of the proc directory entries
 50 */
 51
 52static const char name_root[]         = "vlan";
 53static const char name_conf[]         = "config";
 54
 55/*
 56 *        Structures for interfacing with the /proc filesystem.
 57 *        VLAN creates its own directory /proc/net/vlan with the folowing
 58 *        entries:
 59 *        config                device status/configuration
 60 *        <device>        entry for each  device
 61 */
 62
 63/*
 64 *        Generic /proc/net/vlan/<file> file and inode operations
 65 */
 66
 67static const struct seq_operations vlan_seq_ops = {
 68        .start = vlan_seq_start,
 69        .next = vlan_seq_next,
 70        .stop = vlan_seq_stop,
 71        .show = vlan_seq_show,
 72};
 73
 74static int vlan_seq_open(struct inode *inode, struct file *file)
 75{
 76        return seq_open_net(inode, file, &vlan_seq_ops,
 77                        sizeof(struct seq_net_private));
 78}
 79
 80static const struct file_operations vlan_fops = {
 81        .owner         = THIS_MODULE,
 82        .open    = vlan_seq_open,
 83        .read    = seq_read,
 84        .llseek  = seq_lseek,
 85        .release = seq_release_net,
 86};
 87
 88/*
 89 *        /proc/net/vlan/<device> file and inode operations
 90 */
 91
 92static int vlandev_seq_open(struct inode *inode, struct file *file)
 93{
 94        return single_open(file, vlandev_seq_show, PDE(inode)->data);
 95}
 96
 97static const struct file_operations vlandev_fops = {
 98        .owner = THIS_MODULE,
 99        .open    = vlandev_seq_open,
100        .read    = seq_read,
101        .llseek  = seq_lseek,
102        .release = single_release,
103};
104
105/*
106 * Proc filesystem derectory entries.
107 */
108
109/* Strings */
110static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = {
111    [VLAN_NAME_TYPE_RAW_PLUS_VID]        = "VLAN_NAME_TYPE_RAW_PLUS_VID",
112    [VLAN_NAME_TYPE_PLUS_VID_NO_PAD]         = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD",
113    [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD",
114    [VLAN_NAME_TYPE_PLUS_VID]                 = "VLAN_NAME_TYPE_PLUS_VID",
115};
116/*
117 *        Interface functions
118 */
119
120/*
121 *        Clean up /proc/net/vlan entries
122 */
123
124void vlan_proc_cleanup(struct net *net)
125{
126        struct vlan_net *vn = net_generic(net, vlan_net_id);
127
128        if (vn->proc_vlan_conf)
129                remove_proc_entry(name_conf, vn->proc_vlan_dir);
130
131        if (vn->proc_vlan_dir)
132                proc_net_remove(net, name_root);
133
134        /* Dynamically added entries should be cleaned up as their vlan_device
135         * is removed, so we should not have to take care of it here...
136         */
137}
138
139/*
140 *        Create /proc/net/vlan entries
141 */
142
143int vlan_proc_init(struct net *net)
144{
145        struct vlan_net *vn = net_generic(net, vlan_net_id);
146
147        vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
148        if (!vn->proc_vlan_dir)
149                goto err;
150
151        vn->proc_vlan_conf = proc_create(name_conf, S_IFREG|S_IRUSR|S_IWUSR,
152                                     vn->proc_vlan_dir, &vlan_fops);
153        if (!vn->proc_vlan_conf)
154                goto err;
155        return 0;
156
157err:
158        pr_err("%s: can't create entry in proc filesystem!\n", __func__);
159        vlan_proc_cleanup(net);
160        return -ENOBUFS;
161}
162
163/*
164 *        Add directory entry for VLAN device.
165 */
166
167int vlan_proc_add_dev(struct net_device *vlandev)
168{
169        struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
170        struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
171
172        dev_info->dent =
173                proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
174                                 vn->proc_vlan_dir, &vlandev_fops, vlandev);
175        if (!dev_info->dent)
176                return -ENOBUFS;
177        return 0;
178}
179
180/*
181 *        Delete directory entry for VLAN device.
182 */
183int vlan_proc_rem_dev(struct net_device *vlandev)
184{
185        struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
186
187        /** NOTE:  This will consume the memory pointed to by dent, it seems. */
188        if (vlan_dev_info(vlandev)->dent) {
189                remove_proc_entry(vlan_dev_info(vlandev)->dent->name,
190                                  vn->proc_vlan_dir);
191                vlan_dev_info(vlandev)->dent = NULL;
192        }
193        return 0;
194}
195
196/****** Proc filesystem entry points ****************************************/
197
198/*
199 * The following few functions build the content of /proc/net/vlan/config
200 */
201
202/* start read of /proc/net/vlan/config */
203static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
204        __acquires(dev_base_lock)
205{
206        struct net_device *dev;
207        struct net *net = seq_file_net(seq);
208        loff_t i = 1;
209
210        read_lock(&dev_base_lock);
211
212        if (*pos == 0)
213                return SEQ_START_TOKEN;
214
215        for_each_netdev(net, dev) {
216                if (!is_vlan_dev(dev))
217                        continue;
218
219                if (i++ == *pos)
220                        return dev;
221        }
222
223        return  NULL;
224}
225
226static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
227{
228        struct net_device *dev;
229        struct net *net = seq_file_net(seq);
230
231        ++*pos;
232
233        dev = (struct net_device *)v;
234        if (v == SEQ_START_TOKEN)
235                dev = net_device_entry(&net->dev_base_head);
236
237        for_each_netdev_continue(net, dev) {
238                if (!is_vlan_dev(dev))
239                        continue;
240
241                return dev;
242        }
243
244        return NULL;
245}
246
247static void vlan_seq_stop(struct seq_file *seq, void *v)
248        __releases(dev_base_lock)
249{
250        read_unlock(&dev_base_lock);
251}
252
253static int vlan_seq_show(struct seq_file *seq, void *v)
254{
255        struct net *net = seq_file_net(seq);
256        struct vlan_net *vn = net_generic(net, vlan_net_id);
257
258        if (v == SEQ_START_TOKEN) {
259                const char *nmtype = NULL;
260
261                seq_puts(seq, "VLAN Dev name         | VLAN ID\n");
262
263                if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
264                    nmtype =  vlan_name_type_str[vn->name_type];
265
266                seq_printf(seq, "Name-Type: %s\n",
267                           nmtype ? nmtype :  "UNKNOWN");
268        } else {
269                const struct net_device *vlandev = v;
270                const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
271
272                seq_printf(seq, "%-15s| %d  | %s\n",  vlandev->name,
273                           dev_info->vlan_id,    dev_info->real_dev->name);
274        }
275        return 0;
276}
277
278static int vlandev_seq_show(struct seq_file *seq, void *offset)
279{
280        struct net_device *vlandev = (struct net_device *) seq->private;
281        const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
282        struct net_device_stats *stats = &vlandev->stats;
283        static const char fmt[] = "%30s %12lu\n";
284        int i;
285
286        if (!is_vlan_dev(vlandev))
287                return 0;
288
289        seq_printf(seq,
290                   "%s  VID: %d         REORDER_HDR: %i  dev->priv_flags: %hx\n",
291                   vlandev->name, dev_info->vlan_id,
292                   (int)(dev_info->flags & 1), vlandev->priv_flags);
293
294        seq_printf(seq, fmt, "total frames received", stats->rx_packets);
295        seq_printf(seq, fmt, "total bytes received", stats->rx_bytes);
296        seq_printf(seq, fmt, "Broadcast/Multicast Rcvd", stats->multicast);
297        seq_puts(seq, "\n");
298        seq_printf(seq, fmt, "total frames transmitted", stats->tx_packets);
299        seq_printf(seq, fmt, "total bytes transmitted", stats->tx_bytes);
300        seq_printf(seq, fmt, "total headroom inc",
301                   dev_info->cnt_inc_headroom_on_tx);
302        seq_printf(seq, fmt, "total encap on xmit",
303                   dev_info->cnt_encap_on_xmit);
304        seq_printf(seq, "Device: %s", dev_info->real_dev->name);
305        /* now show all PRIORITY mappings relating to this VLAN */
306        seq_printf(seq, "\nINGRESS priority mappings: "
307                        "0:%u  1:%u  2:%u  3:%u  4:%u  5:%u  6:%u 7:%u\n",
308                   dev_info->ingress_priority_map[0],
309                   dev_info->ingress_priority_map[1],
310                   dev_info->ingress_priority_map[2],
311                   dev_info->ingress_priority_map[3],
312                   dev_info->ingress_priority_map[4],
313                   dev_info->ingress_priority_map[5],
314                   dev_info->ingress_priority_map[6],
315                   dev_info->ingress_priority_map[7]);
316
317        seq_printf(seq, " EGRESS priority mappings: ");
318        for (i = 0; i < 16; i++) {
319                const struct vlan_priority_tci_mapping *mp
320                        = dev_info->egress_priority_map[i];
321                while (mp) {
322                        seq_printf(seq, "%u:%hu ",
323                                   mp->priority, ((mp->vlan_qos >> 13) & 0x7));
324                        mp = mp->next;
325                }
326        }
327        seq_puts(seq, "\n");
328
329        return 0;
330}