aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/bin.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/bin.c')
-rw-r--r--fs/sysfs/bin.c95
1 files changed, 62 insertions, 33 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 5dc47fe5de5e..618b8aea6a7b 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -23,6 +23,7 @@
23struct bin_buffer { 23struct bin_buffer {
24 struct mutex mutex; 24 struct mutex mutex;
25 void *buffer; 25 void *buffer;
26 int mmapped;
26}; 27};
27 28
28static int 29static int
@@ -30,12 +31,20 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
30{ 31{
31 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 32 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
32 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 33 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
33 struct kobject * kobj = to_kobj(dentry->d_parent); 34 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
35 int rc;
36
37 /* need attr_sd for attr, its parent for kobj */
38 if (!sysfs_get_active_two(attr_sd))
39 return -ENODEV;
34 40
35 if (!attr->read) 41 rc = -EIO;
36 return -EIO; 42 if (attr->read)
43 rc = attr->read(kobj, buffer, off, count);
37 44
38 return attr->read(kobj, buffer, off, count); 45 sysfs_put_active_two(attr_sd);
46
47 return rc;
39} 48}
40 49
41static ssize_t 50static ssize_t
@@ -79,12 +88,20 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
79{ 88{
80 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 89 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
81 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 90 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
82 struct kobject *kobj = to_kobj(dentry->d_parent); 91 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
92 int rc;
93
94 /* need attr_sd for attr, its parent for kobj */
95 if (!sysfs_get_active_two(attr_sd))
96 return -ENODEV;
83 97
84 if (!attr->write) 98 rc = -EIO;
85 return -EIO; 99 if (attr->write)
100 rc = attr->write(kobj, buffer, offset, count);
86 101
87 return attr->write(kobj, buffer, offset, count); 102 sysfs_put_active_two(attr_sd);
103
104 return rc;
88} 105}
89 106
90static ssize_t write(struct file *file, const char __user *userbuf, 107static ssize_t write(struct file *file, const char __user *userbuf,
@@ -124,14 +141,24 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
124 struct bin_buffer *bb = file->private_data; 141 struct bin_buffer *bb = file->private_data;
125 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 142 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
126 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 143 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
127 struct kobject *kobj = to_kobj(file->f_path.dentry->d_parent); 144 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
128 int rc; 145 int rc;
129 146
130 if (!attr->mmap)
131 return -EINVAL;
132
133 mutex_lock(&bb->mutex); 147 mutex_lock(&bb->mutex);
134 rc = attr->mmap(kobj, attr, vma); 148
149 /* need attr_sd for attr, its parent for kobj */
150 if (!sysfs_get_active_two(attr_sd))
151 return -ENODEV;
152
153 rc = -EINVAL;
154 if (attr->mmap)
155 rc = attr->mmap(kobj, attr, vma);
156
157 if (rc == 0 && !bb->mmapped)
158 bb->mmapped = 1;
159 else
160 sysfs_put_active_two(attr_sd);
161
135 mutex_unlock(&bb->mutex); 162 mutex_unlock(&bb->mutex);
136 163
137 return rc; 164 return rc;
@@ -139,58 +166,60 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
139 166
140static int open(struct inode * inode, struct file * file) 167static int open(struct inode * inode, struct file * file)
141{ 168{
142 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
143 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 169 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
144 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 170 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
145 struct bin_buffer *bb = NULL; 171 struct bin_buffer *bb = NULL;
146 int error = -EINVAL; 172 int error;
147 173
148 if (!kobj || !attr) 174 /* need attr_sd for attr */
149 goto Done; 175 if (!sysfs_get_active(attr_sd))
176 return -ENODEV;
150 177
151 /* Grab the module reference for this attribute if we have one */ 178 /* Grab the module reference for this attribute */
152 error = -ENODEV; 179 error = -ENODEV;
153 if (!try_module_get(attr->attr.owner)) 180 if (!try_module_get(attr->attr.owner))
154 goto Done; 181 goto err_sput;
155 182
156 error = -EACCES; 183 error = -EACCES;
157 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 184 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
158 goto Error; 185 goto err_mput;
159 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 186 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
160 goto Error; 187 goto err_mput;
161 188
162 error = -ENOMEM; 189 error = -ENOMEM;
163 bb = kzalloc(sizeof(*bb), GFP_KERNEL); 190 bb = kzalloc(sizeof(*bb), GFP_KERNEL);
164 if (!bb) 191 if (!bb)
165 goto Error; 192 goto err_mput;
166 193
167 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 194 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
168 if (!bb->buffer) 195 if (!bb->buffer)
169 goto Error; 196 goto err_mput;
170 197
171 mutex_init(&bb->mutex); 198 mutex_init(&bb->mutex);
172 file->private_data = bb; 199 file->private_data = bb;
173 200
174 error = 0; 201 /* open succeeded, put active reference and pin attr_sd */
175 goto Done; 202 sysfs_put_active(attr_sd);
203 sysfs_get(attr_sd);
204 return 0;
176 205
177 Error: 206 err_mput:
178 kfree(bb);
179 module_put(attr->attr.owner); 207 module_put(attr->attr.owner);
180 Done: 208 err_sput:
181 if (error) 209 sysfs_put_active(attr_sd);
182 kobject_put(kobj); 210 kfree(bb);
183 return error; 211 return error;
184} 212}
185 213
186static int release(struct inode * inode, struct file * file) 214static int release(struct inode * inode, struct file * file)
187{ 215{
188 struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
189 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 216 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
190 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; 217 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
191 struct bin_buffer *bb = file->private_data; 218 struct bin_buffer *bb = file->private_data;
192 219
193 kobject_put(kobj); 220 if (bb->mmapped)
221 sysfs_put_active_two(attr_sd);
222 sysfs_put(attr_sd);
194 module_put(attr->attr.owner); 223 module_put(attr->attr.owner);
195 kfree(bb->buffer); 224 kfree(bb->buffer);
196 kfree(bb); 225 kfree(bb);