Showing error 926

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: fs/sysfs/bin.c
Line in file: 177
Project: Linux Kernel
Project version: 2.6.28
Confirmation: Fixed by e0edd3c65aa5b53e20280565a7ce11675eb7ed6b
Tools: Stanse (1.2)
Entered: 2012-03-02 21:35:17 UTC


Source:

  1/*
  2 * fs/sysfs/bin.c - sysfs binary file implementation
  3 *
  4 * Copyright (c) 2003 Patrick Mochel
  5 * Copyright (c) 2003 Matthew Wilcox
  6 * Copyright (c) 2004 Silicon Graphics, Inc.
  7 * Copyright (c) 2007 SUSE Linux Products GmbH
  8 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
  9 *
 10 * This file is released under the GPLv2.
 11 *
 12 * Please see Documentation/filesystems/sysfs.txt for more information.
 13 */
 14
 15#undef DEBUG
 16
 17#include <linux/errno.h>
 18#include <linux/fs.h>
 19#include <linux/kernel.h>
 20#include <linux/kobject.h>
 21#include <linux/module.h>
 22#include <linux/slab.h>
 23#include <linux/mutex.h>
 24
 25#include <asm/uaccess.h>
 26
 27#include "sysfs.h"
 28
 29struct bin_buffer {
 30        struct mutex        mutex;
 31        void                *buffer;
 32        int                mmapped;
 33};
 34
 35static int
 36fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 37{
 38        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
 39        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
 40        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 41        int rc;
 42
 43        /* need attr_sd for attr, its parent for kobj */
 44        if (!sysfs_get_active_two(attr_sd))
 45                return -ENODEV;
 46
 47        rc = -EIO;
 48        if (attr->read)
 49                rc = attr->read(kobj, attr, buffer, off, count);
 50
 51        sysfs_put_active_two(attr_sd);
 52
 53        return rc;
 54}
 55
 56static ssize_t
 57read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
 58{
 59        struct bin_buffer *bb = file->private_data;
 60        struct dentry *dentry = file->f_path.dentry;
 61        int size = dentry->d_inode->i_size;
 62        loff_t offs = *off;
 63        int count = min_t(size_t, bytes, PAGE_SIZE);
 64        char *temp;
 65
 66        if (size) {
 67                if (offs > size)
 68                        return 0;
 69                if (offs + count > size)
 70                        count = size - offs;
 71        }
 72
 73        temp = kmalloc(count, GFP_KERNEL);
 74        if (!temp)
 75                return -ENOMEM;
 76
 77        mutex_lock(&bb->mutex);
 78
 79        count = fill_read(dentry, bb->buffer, offs, count);
 80        if (count < 0) {
 81                mutex_unlock(&bb->mutex);
 82                goto out_free;
 83        }
 84
 85        memcpy(temp, bb->buffer, count);
 86
 87        mutex_unlock(&bb->mutex);
 88
 89        if (copy_to_user(userbuf, temp, count)) {
 90                count = -EFAULT;
 91                goto out_free;
 92        }
 93
 94        pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
 95
 96        *off = offs + count;
 97
 98 out_free:
 99        kfree(temp);
100        return count;
101}
102
103static int
104flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
105{
106        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
107        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
108        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
109        int rc;
110
111        /* need attr_sd for attr, its parent for kobj */
112        if (!sysfs_get_active_two(attr_sd))
113                return -ENODEV;
114
115        rc = -EIO;
116        if (attr->write)
117                rc = attr->write(kobj, attr, buffer, offset, count);
118
119        sysfs_put_active_two(attr_sd);
120
121        return rc;
122}
123
124static ssize_t write(struct file *file, const char __user *userbuf,
125                     size_t bytes, loff_t *off)
126{
127        struct bin_buffer *bb = file->private_data;
128        struct dentry *dentry = file->f_path.dentry;
129        int size = dentry->d_inode->i_size;
130        loff_t offs = *off;
131        int count = min_t(size_t, bytes, PAGE_SIZE);
132        char *temp;
133
134        if (size) {
135                if (offs > size)
136                        return 0;
137                if (offs + count > size)
138                        count = size - offs;
139        }
140
141        temp = kmalloc(count, GFP_KERNEL);
142        if (!temp)
143                return -ENOMEM;
144
145        if (copy_from_user(temp, userbuf, count)) {
146                count = -EFAULT;
147                goto out_free;
148        }
149
150        mutex_lock(&bb->mutex);
151
152        memcpy(bb->buffer, temp, count);
153
154        count = flush_write(dentry, bb->buffer, offs, count);
155        mutex_unlock(&bb->mutex);
156
157        if (count > 0)
158                *off = offs + count;
159
160out_free:
161        kfree(temp);
162        return count;
163}
164
165static int mmap(struct file *file, struct vm_area_struct *vma)
166{
167        struct bin_buffer *bb = file->private_data;
168        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
169        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
170        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
171        int rc;
172
173        mutex_lock(&bb->mutex);
174
175        /* need attr_sd for attr, its parent for kobj */
176        if (!sysfs_get_active_two(attr_sd))
177                return -ENODEV;
178
179        rc = -EINVAL;
180        if (attr->mmap)
181                rc = attr->mmap(kobj, attr, vma);
182
183        if (rc == 0 && !bb->mmapped)
184                bb->mmapped = 1;
185        else
186                sysfs_put_active_two(attr_sd);
187
188        mutex_unlock(&bb->mutex);
189
190        return rc;
191}
192
193static int open(struct inode * inode, struct file * file)
194{
195        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
196        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
197        struct bin_buffer *bb = NULL;
198        int error;
199
200        /* binary file operations requires both @sd and its parent */
201        if (!sysfs_get_active_two(attr_sd))
202                return -ENODEV;
203
204        error = -EACCES;
205        if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
206                goto err_out;
207        if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
208                goto err_out;
209
210        error = -ENOMEM;
211        bb = kzalloc(sizeof(*bb), GFP_KERNEL);
212        if (!bb)
213                goto err_out;
214
215        bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
216        if (!bb->buffer)
217                goto err_out;
218
219        mutex_init(&bb->mutex);
220        file->private_data = bb;
221
222        /* open succeeded, put active references */
223        sysfs_put_active_two(attr_sd);
224        return 0;
225
226 err_out:
227        sysfs_put_active_two(attr_sd);
228        kfree(bb);
229        return error;
230}
231
232static int release(struct inode * inode, struct file * file)
233{
234        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
235        struct bin_buffer *bb = file->private_data;
236
237        if (bb->mmapped)
238                sysfs_put_active_two(attr_sd);
239        kfree(bb->buffer);
240        kfree(bb);
241        return 0;
242}
243
244const struct file_operations bin_fops = {
245        .read                = read,
246        .write                = write,
247        .mmap                = mmap,
248        .llseek                = generic_file_llseek,
249        .open                = open,
250        .release        = release,
251};
252
253/**
254 *        sysfs_create_bin_file - create binary file for object.
255 *        @kobj:        object.
256 *        @attr:        attribute descriptor.
257 */
258
259int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
260{
261        BUG_ON(!kobj || !kobj->sd || !attr);
262
263        return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
264}
265
266
267/**
268 *        sysfs_remove_bin_file - remove binary file for object.
269 *        @kobj:        object.
270 *        @attr:        attribute descriptor.
271 */
272
273void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
274{
275        sysfs_hash_and_remove(kobj->sd, attr->attr.name);
276}
277
278EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
279EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);