diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 130 |
1 files changed, 76 insertions, 54 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 04f6b0ebc889..310430baf572 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -87,8 +87,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | |||
87 | */ | 87 | */ |
88 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 88 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
89 | { | 89 | { |
90 | struct sysfs_dirent * sd = dentry->d_fsdata; | 90 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
91 | struct kobject * kobj = to_kobj(dentry->d_parent); | 91 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
92 | struct sysfs_ops * ops = buffer->ops; | 92 | struct sysfs_ops * ops = buffer->ops; |
93 | int ret = 0; | 93 | int ret = 0; |
94 | ssize_t count; | 94 | ssize_t count; |
@@ -98,8 +98,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
98 | if (!buffer->page) | 98 | if (!buffer->page) |
99 | return -ENOMEM; | 99 | return -ENOMEM; |
100 | 100 | ||
101 | buffer->event = atomic_read(&sd->s_event); | 101 | /* need attr_sd for attr and ops, its parent for kobj */ |
102 | count = ops->show(kobj, sd->s_elem.attr.attr, buffer->page); | 102 | if (!sysfs_get_active_two(attr_sd)) |
103 | return -ENODEV; | ||
104 | |||
105 | buffer->event = atomic_read(&attr_sd->s_event); | ||
106 | count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); | ||
107 | |||
108 | sysfs_put_active_two(attr_sd); | ||
109 | |||
103 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 110 | BUG_ON(count > (ssize_t)PAGE_SIZE); |
104 | if (count >= 0) { | 111 | if (count >= 0) { |
105 | buffer->needs_read_fill = 0; | 112 | buffer->needs_read_fill = 0; |
@@ -195,14 +202,23 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
195 | * passing the buffer that we acquired in fill_write_buffer(). | 202 | * passing the buffer that we acquired in fill_write_buffer(). |
196 | */ | 203 | */ |
197 | 204 | ||
198 | static int | 205 | static int |
199 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) | 206 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) |
200 | { | 207 | { |
201 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 208 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
202 | struct kobject * kobj = to_kobj(dentry->d_parent); | 209 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
203 | struct sysfs_ops * ops = buffer->ops; | 210 | struct sysfs_ops * ops = buffer->ops; |
211 | int rc; | ||
212 | |||
213 | /* need attr_sd for attr and ops, its parent for kobj */ | ||
214 | if (!sysfs_get_active_two(attr_sd)) | ||
215 | return -ENODEV; | ||
216 | |||
217 | rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); | ||
218 | |||
219 | sysfs_put_active_two(attr_sd); | ||
204 | 220 | ||
205 | return ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); | 221 | return rc; |
206 | } | 222 | } |
207 | 223 | ||
208 | 224 | ||
@@ -246,22 +262,22 @@ out: | |||
246 | 262 | ||
247 | static int sysfs_open_file(struct inode *inode, struct file *file) | 263 | static int sysfs_open_file(struct inode *inode, struct file *file) |
248 | { | 264 | { |
249 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); | ||
250 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 265 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
251 | struct attribute *attr = attr_sd->s_elem.attr.attr; | 266 | struct attribute *attr = attr_sd->s_elem.attr.attr; |
267 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | ||
252 | struct sysfs_buffer_collection *set; | 268 | struct sysfs_buffer_collection *set; |
253 | struct sysfs_buffer * buffer; | 269 | struct sysfs_buffer * buffer; |
254 | struct sysfs_ops * ops = NULL; | 270 | struct sysfs_ops * ops = NULL; |
255 | int error = 0; | 271 | int error; |
256 | 272 | ||
257 | if (!kobj || !attr) | 273 | /* need attr_sd for attr and ops, its parent for kobj */ |
258 | goto Einval; | 274 | if (!sysfs_get_active_two(attr_sd)) |
275 | return -ENODEV; | ||
259 | 276 | ||
260 | /* Grab the module reference for this attribute if we have one */ | 277 | /* Grab the module reference for this attribute */ |
261 | if (!try_module_get(attr->owner)) { | 278 | error = -ENODEV; |
262 | error = -ENODEV; | 279 | if (!try_module_get(attr->owner)) |
263 | goto Done; | 280 | goto err_sput; |
264 | } | ||
265 | 281 | ||
266 | /* if the kobject has no ktype, then we assume that it is a subsystem | 282 | /* if the kobject has no ktype, then we assume that it is a subsystem |
267 | * itself, and use ops for it. | 283 | * itself, and use ops for it. |
@@ -276,30 +292,30 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
276 | /* No sysfs operations, either from having no subsystem, | 292 | /* No sysfs operations, either from having no subsystem, |
277 | * or the subsystem have no operations. | 293 | * or the subsystem have no operations. |
278 | */ | 294 | */ |
295 | error = -EACCES; | ||
279 | if (!ops) | 296 | if (!ops) |
280 | goto Eaccess; | 297 | goto err_mput; |
281 | 298 | ||
282 | /* make sure we have a collection to add our buffers to */ | 299 | /* make sure we have a collection to add our buffers to */ |
283 | mutex_lock(&inode->i_mutex); | 300 | mutex_lock(&inode->i_mutex); |
284 | if (!(set = inode->i_private)) { | 301 | if (!(set = inode->i_private)) { |
285 | if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { | 302 | error = -ENOMEM; |
286 | error = -ENOMEM; | 303 | if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) |
287 | goto Done; | 304 | goto err_mput; |
288 | } else { | 305 | else |
289 | INIT_LIST_HEAD(&set->associates); | 306 | INIT_LIST_HEAD(&set->associates); |
290 | } | ||
291 | } | 307 | } |
292 | mutex_unlock(&inode->i_mutex); | 308 | mutex_unlock(&inode->i_mutex); |
293 | 309 | ||
310 | error = -EACCES; | ||
311 | |||
294 | /* File needs write support. | 312 | /* File needs write support. |
295 | * The inode's perms must say it's ok, | 313 | * The inode's perms must say it's ok, |
296 | * and we must have a store method. | 314 | * and we must have a store method. |
297 | */ | 315 | */ |
298 | if (file->f_mode & FMODE_WRITE) { | 316 | if (file->f_mode & FMODE_WRITE) { |
299 | |||
300 | if (!(inode->i_mode & S_IWUGO) || !ops->store) | 317 | if (!(inode->i_mode & S_IWUGO) || !ops->store) |
301 | goto Eaccess; | 318 | goto err_mput; |
302 | |||
303 | } | 319 | } |
304 | 320 | ||
305 | /* File needs read support. | 321 | /* File needs read support. |
@@ -308,46 +324,45 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
308 | */ | 324 | */ |
309 | if (file->f_mode & FMODE_READ) { | 325 | if (file->f_mode & FMODE_READ) { |
310 | if (!(inode->i_mode & S_IRUGO) || !ops->show) | 326 | if (!(inode->i_mode & S_IRUGO) || !ops->show) |
311 | goto Eaccess; | 327 | goto err_mput; |
312 | } | 328 | } |
313 | 329 | ||
314 | /* No error? Great, allocate a buffer for the file, and store it | 330 | /* No error? Great, allocate a buffer for the file, and store it |
315 | * it in file->private_data for easy access. | 331 | * it in file->private_data for easy access. |
316 | */ | 332 | */ |
333 | error = -ENOMEM; | ||
317 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); | 334 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); |
318 | if (buffer) { | 335 | if (!buffer) |
319 | INIT_LIST_HEAD(&buffer->associates); | 336 | goto err_mput; |
320 | init_MUTEX(&buffer->sem); | ||
321 | buffer->needs_read_fill = 1; | ||
322 | buffer->ops = ops; | ||
323 | add_to_collection(buffer, inode); | ||
324 | file->private_data = buffer; | ||
325 | } else | ||
326 | error = -ENOMEM; | ||
327 | goto Done; | ||
328 | 337 | ||
329 | Einval: | 338 | INIT_LIST_HEAD(&buffer->associates); |
330 | error = -EINVAL; | 339 | init_MUTEX(&buffer->sem); |
331 | goto Done; | 340 | buffer->needs_read_fill = 1; |
332 | Eaccess: | 341 | buffer->ops = ops; |
333 | error = -EACCES; | 342 | add_to_collection(buffer, inode); |
343 | file->private_data = buffer; | ||
344 | |||
345 | /* open succeeded, put active references and pin attr_sd */ | ||
346 | sysfs_put_active_two(attr_sd); | ||
347 | sysfs_get(attr_sd); | ||
348 | return 0; | ||
349 | |||
350 | err_mput: | ||
334 | module_put(attr->owner); | 351 | module_put(attr->owner); |
335 | Done: | 352 | err_sput: |
336 | if (error) | 353 | sysfs_put_active_two(attr_sd); |
337 | kobject_put(kobj); | ||
338 | return error; | 354 | return error; |
339 | } | 355 | } |
340 | 356 | ||
341 | static int sysfs_release(struct inode * inode, struct file * filp) | 357 | static int sysfs_release(struct inode * inode, struct file * filp) |
342 | { | 358 | { |
343 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | ||
344 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 359 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
345 | struct attribute *attr = attr_sd->s_elem.attr.attr; | 360 | struct attribute *attr = attr_sd->s_elem.attr.attr; |
346 | struct sysfs_buffer * buffer = filp->private_data; | 361 | struct sysfs_buffer * buffer = filp->private_data; |
347 | 362 | ||
348 | if (buffer) | 363 | if (buffer) |
349 | remove_from_collection(buffer, inode); | 364 | remove_from_collection(buffer, inode); |
350 | kobject_put(kobj); | 365 | sysfs_put(attr_sd); |
351 | /* After this point, attr should not be accessed. */ | 366 | /* After this point, attr should not be accessed. */ |
352 | module_put(attr->owner); | 367 | module_put(attr->owner); |
353 | 368 | ||
@@ -376,18 +391,25 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
376 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 391 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
377 | { | 392 | { |
378 | struct sysfs_buffer * buffer = filp->private_data; | 393 | struct sysfs_buffer * buffer = filp->private_data; |
379 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 394 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
380 | struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata; | 395 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
381 | int res = 0; | 396 | |
397 | /* need parent for the kobj, grab both */ | ||
398 | if (!sysfs_get_active_two(attr_sd)) | ||
399 | goto trigger; | ||
382 | 400 | ||
383 | poll_wait(filp, &kobj->poll, wait); | 401 | poll_wait(filp, &kobj->poll, wait); |
384 | 402 | ||
385 | if (buffer->event != atomic_read(&sd->s_event)) { | 403 | sysfs_put_active_two(attr_sd); |
386 | res = POLLERR|POLLPRI; | ||
387 | buffer->needs_read_fill = 1; | ||
388 | } | ||
389 | 404 | ||
390 | return res; | 405 | if (buffer->event != atomic_read(&attr_sd->s_event)) |
406 | goto trigger; | ||
407 | |||
408 | return 0; | ||
409 | |||
410 | trigger: | ||
411 | buffer->needs_read_fill = 1; | ||
412 | return POLLERR|POLLPRI; | ||
391 | } | 413 | } |
392 | 414 | ||
393 | 415 | ||