aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/bin.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 67a0d5030c96..5dc47fe5de5e 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -20,6 +20,11 @@
20 20
21#include "sysfs.h" 21#include "sysfs.h"
22 22
23struct bin_buffer {
24 struct mutex mutex;
25 void *buffer;
26};
27
23static int 28static int
24fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) 29fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
25{ 30{
@@ -36,7 +41,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
36static ssize_t 41static ssize_t
37read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) 42read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
38{ 43{
39 char *buffer = file->private_data; 44 struct bin_buffer *bb = file->private_data;
40 struct dentry *dentry = file->f_path.dentry; 45 struct dentry *dentry = file->f_path.dentry;
41 int size = dentry->d_inode->i_size; 46 int size = dentry->d_inode->i_size;
42 loff_t offs = *off; 47 loff_t offs = *off;
@@ -49,17 +54,23 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
49 count = size - offs; 54 count = size - offs;
50 } 55 }
51 56
52 count = fill_read(dentry, buffer, offs, count); 57 mutex_lock(&bb->mutex);
58
59 count = fill_read(dentry, bb->buffer, offs, count);
53 if (count < 0) 60 if (count < 0)
54 return count; 61 goto out_unlock;
55 62
56 if (copy_to_user(userbuf, buffer, count)) 63 if (copy_to_user(userbuf, bb->buffer, count)) {
57 return -EFAULT; 64 count = -EFAULT;
65 goto out_unlock;
66 }
58 67
59 pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); 68 pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
60 69
61 *off = offs + count; 70 *off = offs + count;
62 71
72 out_unlock:
73 mutex_unlock(&bb->mutex);
63 return count; 74 return count;
64} 75}
65 76
@@ -79,7 +90,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
79static ssize_t write(struct file *file, const char __user *userbuf, 90static ssize_t write(struct file *file, const char __user *userbuf,
80 size_t bytes, loff_t *off) 91 size_t bytes, loff_t *off)
81{ 92{
82 char *buffer = file->private_data; 93 struct bin_buffer *bb = file->private_data;
83 struct dentry *dentry = file->f_path.dentry; 94 struct dentry *dentry = file->f_path.dentry;
84 int size = dentry->d_inode->i_size; 95 int size = dentry->d_inode->i_size;
85 loff_t offs = *off; 96 loff_t offs = *off;
@@ -92,25 +103,38 @@ static ssize_t write(struct file *file, const char __user *userbuf,
92 count = size - offs; 103 count = size - offs;
93 } 104 }
94 105
95 if (copy_from_user(buffer, userbuf, count)) 106 mutex_lock(&bb->mutex);
96 return -EFAULT; 107
108 if (copy_from_user(bb->buffer, userbuf, count)) {
109 count = -EFAULT;
110 goto out_unlock;
111 }
97 112
98 count = flush_write(dentry, buffer, offs, count); 113 count = flush_write(dentry, bb->buffer, offs, count);
99 if (count > 0) 114 if (count > 0)
100 *off = offs + count; 115 *off = offs + count;
116
117 out_unlock:
118 mutex_unlock(&bb->mutex);
101 return count; 119 return count;
102} 120}
103 121
104static int mmap(struct file *file, struct vm_area_struct *vma) 122static int mmap(struct file *file, struct vm_area_struct *vma)
105{ 123{
124 struct bin_buffer *bb = file->private_data;
106 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 125 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
107 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 126 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
108 struct kobject *kobj = to_kobj(file->f_path.dentry->d_parent); 127 struct kobject *kobj = to_kobj(file->f_path.dentry->d_parent);
128 int rc;
109 129
110 if (!attr->mmap) 130 if (!attr->mmap)
111 return -EINVAL; 131 return -EINVAL;
112 132
113 return attr->mmap(kobj, attr, vma); 133 mutex_lock(&bb->mutex);
134 rc = attr->mmap(kobj, attr, vma);
135 mutex_unlock(&bb->mutex);
136
137 return rc;
114} 138}
115 139
116static int open(struct inode * inode, struct file * file) 140static int open(struct inode * inode, struct file * file)
@@ -118,6 +142,7 @@ static int open(struct inode * inode, struct file * file)
118 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); 142 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
119 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 143 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
120 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 144 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
145 struct bin_buffer *bb = NULL;
121 int error = -EINVAL; 146 int error = -EINVAL;
122 147
123 if (!kobj || !attr) 148 if (!kobj || !attr)
@@ -135,14 +160,22 @@ static int open(struct inode * inode, struct file * file)
135 goto Error; 160 goto Error;
136 161
137 error = -ENOMEM; 162 error = -ENOMEM;
138 file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); 163 bb = kzalloc(sizeof(*bb), GFP_KERNEL);
139 if (!file->private_data) 164 if (!bb)
140 goto Error; 165 goto Error;
141 166
167 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
168 if (!bb->buffer)
169 goto Error;
170
171 mutex_init(&bb->mutex);
172 file->private_data = bb;
173
142 error = 0; 174 error = 0;
143 goto Done; 175 goto Done;
144 176
145 Error: 177 Error:
178 kfree(bb);
146 module_put(attr->attr.owner); 179 module_put(attr->attr.owner);
147 Done: 180 Done:
148 if (error) 181 if (error)
@@ -155,11 +188,12 @@ static int release(struct inode * inode, struct file * file)
155 struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent); 188 struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
156 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 189 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
157 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 190 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
158 u8 * buffer = file->private_data; 191 struct bin_buffer *bb = file->private_data;
159 192
160 kobject_put(kobj); 193 kobject_put(kobj);
161 module_put(attr->attr.owner); 194 module_put(attr->attr.owner);
162 kfree(buffer); 195 kfree(bb->buffer);
196 kfree(bb);
163 return 0; 197 return 0;
164} 198}
165 199