diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 379 |
1 files changed, 173 insertions, 206 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b502c7197ec0..cc497994b2a8 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -50,29 +50,15 @@ static struct sysfs_ops subsys_sysfs_ops = { | |||
50 | .store = subsys_attr_store, | 50 | .store = subsys_attr_store, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /** | 53 | struct sysfs_buffer { |
54 | * add_to_collection - add buffer to a collection | 54 | size_t count; |
55 | * @buffer: buffer to be added | 55 | loff_t pos; |
56 | * @node: inode of set to add to | 56 | char * page; |
57 | */ | 57 | struct sysfs_ops * ops; |
58 | 58 | struct semaphore sem; | |
59 | static inline void | 59 | int needs_read_fill; |
60 | add_to_collection(struct sysfs_buffer *buffer, struct inode *node) | 60 | int event; |
61 | { | 61 | }; |
62 | struct sysfs_buffer_collection *set = node->i_private; | ||
63 | |||
64 | mutex_lock(&node->i_mutex); | ||
65 | list_add(&buffer->associates, &set->associates); | ||
66 | mutex_unlock(&node->i_mutex); | ||
67 | } | ||
68 | |||
69 | static inline void | ||
70 | remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | ||
71 | { | ||
72 | mutex_lock(&node->i_mutex); | ||
73 | list_del(&buffer->associates); | ||
74 | mutex_unlock(&node->i_mutex); | ||
75 | } | ||
76 | 62 | ||
77 | /** | 63 | /** |
78 | * fill_read_buffer - allocate and fill buffer from object. | 64 | * fill_read_buffer - allocate and fill buffer from object. |
@@ -87,9 +73,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | |||
87 | */ | 73 | */ |
88 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 74 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
89 | { | 75 | { |
90 | struct sysfs_dirent * sd = dentry->d_fsdata; | 76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
91 | struct attribute * attr = to_attr(dentry); | 77 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
92 | struct kobject * kobj = to_kobj(dentry->d_parent); | ||
93 | struct sysfs_ops * ops = buffer->ops; | 78 | struct sysfs_ops * ops = buffer->ops; |
94 | int ret = 0; | 79 | int ret = 0; |
95 | ssize_t count; | 80 | ssize_t count; |
@@ -99,8 +84,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
99 | if (!buffer->page) | 84 | if (!buffer->page) |
100 | return -ENOMEM; | 85 | return -ENOMEM; |
101 | 86 | ||
102 | buffer->event = atomic_read(&sd->s_event); | 87 | /* need attr_sd for attr and ops, its parent for kobj */ |
103 | count = ops->show(kobj,attr,buffer->page); | 88 | if (!sysfs_get_active_two(attr_sd)) |
89 | return -ENODEV; | ||
90 | |||
91 | buffer->event = atomic_read(&attr_sd->s_event); | ||
92 | count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); | ||
93 | |||
94 | sysfs_put_active_two(attr_sd); | ||
95 | |||
104 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 96 | BUG_ON(count > (ssize_t)PAGE_SIZE); |
105 | if (count >= 0) { | 97 | if (count >= 0) { |
106 | buffer->needs_read_fill = 0; | 98 | buffer->needs_read_fill = 0; |
@@ -138,10 +130,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
138 | 130 | ||
139 | down(&buffer->sem); | 131 | down(&buffer->sem); |
140 | if (buffer->needs_read_fill) { | 132 | if (buffer->needs_read_fill) { |
141 | if (buffer->orphaned) | 133 | retval = fill_read_buffer(file->f_path.dentry,buffer); |
142 | retval = -ENODEV; | ||
143 | else | ||
144 | retval = fill_read_buffer(file->f_path.dentry,buffer); | ||
145 | if (retval) | 134 | if (retval) |
146 | goto out; | 135 | goto out; |
147 | } | 136 | } |
@@ -196,14 +185,23 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
196 | * passing the buffer that we acquired in fill_write_buffer(). | 185 | * passing the buffer that we acquired in fill_write_buffer(). |
197 | */ | 186 | */ |
198 | 187 | ||
199 | static int | 188 | static int |
200 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) | 189 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) |
201 | { | 190 | { |
202 | struct attribute * attr = to_attr(dentry); | 191 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
203 | struct kobject * kobj = to_kobj(dentry->d_parent); | 192 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
204 | struct sysfs_ops * ops = buffer->ops; | 193 | struct sysfs_ops * ops = buffer->ops; |
194 | int rc; | ||
195 | |||
196 | /* need attr_sd for attr and ops, its parent for kobj */ | ||
197 | if (!sysfs_get_active_two(attr_sd)) | ||
198 | return -ENODEV; | ||
199 | |||
200 | rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); | ||
205 | 201 | ||
206 | return ops->store(kobj,attr,buffer->page,count); | 202 | sysfs_put_active_two(attr_sd); |
203 | |||
204 | return rc; | ||
207 | } | 205 | } |
208 | 206 | ||
209 | 207 | ||
@@ -231,37 +229,26 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t | |||
231 | ssize_t len; | 229 | ssize_t len; |
232 | 230 | ||
233 | down(&buffer->sem); | 231 | down(&buffer->sem); |
234 | if (buffer->orphaned) { | ||
235 | len = -ENODEV; | ||
236 | goto out; | ||
237 | } | ||
238 | len = fill_write_buffer(buffer, buf, count); | 232 | len = fill_write_buffer(buffer, buf, count); |
239 | if (len > 0) | 233 | if (len > 0) |
240 | len = flush_write_buffer(file->f_path.dentry, buffer, len); | 234 | len = flush_write_buffer(file->f_path.dentry, buffer, len); |
241 | if (len > 0) | 235 | if (len > 0) |
242 | *ppos += len; | 236 | *ppos += len; |
243 | out: | ||
244 | up(&buffer->sem); | 237 | up(&buffer->sem); |
245 | return len; | 238 | return len; |
246 | } | 239 | } |
247 | 240 | ||
248 | static int sysfs_open_file(struct inode *inode, struct file *file) | 241 | static int sysfs_open_file(struct inode *inode, struct file *file) |
249 | { | 242 | { |
250 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); | 243 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
251 | struct attribute * attr = to_attr(file->f_path.dentry); | 244 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
252 | struct sysfs_buffer_collection *set; | ||
253 | struct sysfs_buffer * buffer; | 245 | struct sysfs_buffer * buffer; |
254 | struct sysfs_ops * ops = NULL; | 246 | struct sysfs_ops * ops = NULL; |
255 | int error = 0; | 247 | int error; |
256 | |||
257 | if (!kobj || !attr) | ||
258 | goto Einval; | ||
259 | 248 | ||
260 | /* Grab the module reference for this attribute if we have one */ | 249 | /* need attr_sd for attr and ops, its parent for kobj */ |
261 | if (!try_module_get(attr->owner)) { | 250 | if (!sysfs_get_active_two(attr_sd)) |
262 | error = -ENODEV; | 251 | return -ENODEV; |
263 | goto Done; | ||
264 | } | ||
265 | 252 | ||
266 | /* if the kobject has no ktype, then we assume that it is a subsystem | 253 | /* if the kobject has no ktype, then we assume that it is a subsystem |
267 | * itself, and use ops for it. | 254 | * itself, and use ops for it. |
@@ -273,33 +260,21 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
273 | else | 260 | else |
274 | ops = &subsys_sysfs_ops; | 261 | ops = &subsys_sysfs_ops; |
275 | 262 | ||
263 | error = -EACCES; | ||
264 | |||
276 | /* No sysfs operations, either from having no subsystem, | 265 | /* No sysfs operations, either from having no subsystem, |
277 | * or the subsystem have no operations. | 266 | * or the subsystem have no operations. |
278 | */ | 267 | */ |
279 | if (!ops) | 268 | if (!ops) |
280 | goto Eaccess; | 269 | goto err_out; |
281 | |||
282 | /* make sure we have a collection to add our buffers to */ | ||
283 | mutex_lock(&inode->i_mutex); | ||
284 | if (!(set = inode->i_private)) { | ||
285 | if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { | ||
286 | error = -ENOMEM; | ||
287 | goto Done; | ||
288 | } else { | ||
289 | INIT_LIST_HEAD(&set->associates); | ||
290 | } | ||
291 | } | ||
292 | mutex_unlock(&inode->i_mutex); | ||
293 | 270 | ||
294 | /* File needs write support. | 271 | /* File needs write support. |
295 | * The inode's perms must say it's ok, | 272 | * The inode's perms must say it's ok, |
296 | * and we must have a store method. | 273 | * and we must have a store method. |
297 | */ | 274 | */ |
298 | if (file->f_mode & FMODE_WRITE) { | 275 | if (file->f_mode & FMODE_WRITE) { |
299 | |||
300 | if (!(inode->i_mode & S_IWUGO) || !ops->store) | 276 | if (!(inode->i_mode & S_IWUGO) || !ops->store) |
301 | goto Eaccess; | 277 | goto err_out; |
302 | |||
303 | } | 278 | } |
304 | 279 | ||
305 | /* File needs read support. | 280 | /* File needs read support. |
@@ -308,48 +283,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
308 | */ | 283 | */ |
309 | if (file->f_mode & FMODE_READ) { | 284 | if (file->f_mode & FMODE_READ) { |
310 | if (!(inode->i_mode & S_IRUGO) || !ops->show) | 285 | if (!(inode->i_mode & S_IRUGO) || !ops->show) |
311 | goto Eaccess; | 286 | goto err_out; |
312 | } | 287 | } |
313 | 288 | ||
314 | /* No error? Great, allocate a buffer for the file, and store it | 289 | /* No error? Great, allocate a buffer for the file, and store it |
315 | * it in file->private_data for easy access. | 290 | * it in file->private_data for easy access. |
316 | */ | 291 | */ |
292 | error = -ENOMEM; | ||
317 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); | 293 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); |
318 | if (buffer) { | 294 | if (!buffer) |
319 | INIT_LIST_HEAD(&buffer->associates); | 295 | goto err_out; |
320 | init_MUTEX(&buffer->sem); | 296 | |
321 | buffer->needs_read_fill = 1; | 297 | init_MUTEX(&buffer->sem); |
322 | buffer->ops = ops; | 298 | buffer->needs_read_fill = 1; |
323 | add_to_collection(buffer, inode); | 299 | buffer->ops = ops; |
324 | file->private_data = buffer; | 300 | file->private_data = buffer; |
325 | } else | 301 | |
326 | error = -ENOMEM; | 302 | /* open succeeded, put active references and pin attr_sd */ |
327 | goto Done; | 303 | sysfs_put_active_two(attr_sd); |
328 | 304 | sysfs_get(attr_sd); | |
329 | Einval: | 305 | return 0; |
330 | error = -EINVAL; | 306 | |
331 | goto Done; | 307 | err_out: |
332 | Eaccess: | 308 | sysfs_put_active_two(attr_sd); |
333 | error = -EACCES; | ||
334 | module_put(attr->owner); | ||
335 | Done: | ||
336 | if (error) | ||
337 | kobject_put(kobj); | ||
338 | return error; | 309 | return error; |
339 | } | 310 | } |
340 | 311 | ||
341 | static int sysfs_release(struct inode * inode, struct file * filp) | 312 | static int sysfs_release(struct inode * inode, struct file * filp) |
342 | { | 313 | { |
343 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 314 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
344 | struct attribute * attr = to_attr(filp->f_path.dentry); | 315 | struct sysfs_buffer *buffer = filp->private_data; |
345 | struct module * owner = attr->owner; | ||
346 | struct sysfs_buffer * buffer = filp->private_data; | ||
347 | 316 | ||
348 | if (buffer) | 317 | sysfs_put(attr_sd); |
349 | remove_from_collection(buffer, inode); | ||
350 | kobject_put(kobj); | ||
351 | /* After this point, attr should not be accessed. */ | ||
352 | module_put(owner); | ||
353 | 318 | ||
354 | if (buffer) { | 319 | if (buffer) { |
355 | if (buffer->page) | 320 | if (buffer->page) |
@@ -376,57 +341,43 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
376 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 341 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
377 | { | 342 | { |
378 | struct sysfs_buffer * buffer = filp->private_data; | 343 | struct sysfs_buffer * buffer = filp->private_data; |
379 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 344 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
380 | struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata; | 345 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
381 | int res = 0; | 346 | |
347 | /* need parent for the kobj, grab both */ | ||
348 | if (!sysfs_get_active_two(attr_sd)) | ||
349 | goto trigger; | ||
382 | 350 | ||
383 | poll_wait(filp, &kobj->poll, wait); | 351 | poll_wait(filp, &kobj->poll, wait); |
384 | 352 | ||
385 | if (buffer->event != atomic_read(&sd->s_event)) { | 353 | sysfs_put_active_two(attr_sd); |
386 | res = POLLERR|POLLPRI; | ||
387 | buffer->needs_read_fill = 1; | ||
388 | } | ||
389 | 354 | ||
390 | return res; | 355 | if (buffer->event != atomic_read(&attr_sd->s_event)) |
391 | } | 356 | goto trigger; |
392 | 357 | ||
358 | return 0; | ||
393 | 359 | ||
394 | static struct dentry *step_down(struct dentry *dir, const char * name) | 360 | trigger: |
395 | { | 361 | buffer->needs_read_fill = 1; |
396 | struct dentry * de; | 362 | return POLLERR|POLLPRI; |
397 | |||
398 | if (dir == NULL || dir->d_inode == NULL) | ||
399 | return NULL; | ||
400 | |||
401 | mutex_lock(&dir->d_inode->i_mutex); | ||
402 | de = lookup_one_len(name, dir, strlen(name)); | ||
403 | mutex_unlock(&dir->d_inode->i_mutex); | ||
404 | dput(dir); | ||
405 | if (IS_ERR(de)) | ||
406 | return NULL; | ||
407 | if (de->d_inode == NULL) { | ||
408 | dput(de); | ||
409 | return NULL; | ||
410 | } | ||
411 | return de; | ||
412 | } | 363 | } |
413 | 364 | ||
414 | void sysfs_notify(struct kobject * k, char *dir, char *attr) | 365 | void sysfs_notify(struct kobject *k, char *dir, char *attr) |
415 | { | 366 | { |
416 | struct dentry *de = k->dentry; | 367 | struct sysfs_dirent *sd = k->sd; |
417 | if (de) | 368 | |
418 | dget(de); | 369 | mutex_lock(&sysfs_mutex); |
419 | if (de && dir) | 370 | |
420 | de = step_down(de, dir); | 371 | if (sd && dir) |
421 | if (de && attr) | 372 | sd = sysfs_find_dirent(sd, dir); |
422 | de = step_down(de, attr); | 373 | if (sd && attr) |
423 | if (de) { | 374 | sd = sysfs_find_dirent(sd, attr); |
424 | struct sysfs_dirent * sd = de->d_fsdata; | 375 | if (sd) { |
425 | if (sd) | 376 | atomic_inc(&sd->s_event); |
426 | atomic_inc(&sd->s_event); | ||
427 | wake_up_interruptible(&k->poll); | 377 | wake_up_interruptible(&k->poll); |
428 | dput(de); | ||
429 | } | 378 | } |
379 | |||
380 | mutex_unlock(&sysfs_mutex); | ||
430 | } | 381 | } |
431 | EXPORT_SYMBOL_GPL(sysfs_notify); | 382 | EXPORT_SYMBOL_GPL(sysfs_notify); |
432 | 383 | ||
@@ -440,19 +391,30 @@ const struct file_operations sysfs_file_operations = { | |||
440 | }; | 391 | }; |
441 | 392 | ||
442 | 393 | ||
443 | int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) | 394 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, |
395 | int type) | ||
444 | { | 396 | { |
445 | struct sysfs_dirent * parent_sd = dir->d_fsdata; | ||
446 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 397 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
447 | int error = -EEXIST; | 398 | struct sysfs_addrm_cxt acxt; |
399 | struct sysfs_dirent *sd; | ||
448 | 400 | ||
449 | mutex_lock(&dir->d_inode->i_mutex); | 401 | sd = sysfs_new_dirent(attr->name, mode, type); |
450 | if (!sysfs_dirent_exist(parent_sd, attr->name)) | 402 | if (!sd) |
451 | error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, | 403 | return -ENOMEM; |
452 | mode, type); | 404 | sd->s_elem.attr.attr = (void *)attr; |
453 | mutex_unlock(&dir->d_inode->i_mutex); | ||
454 | 405 | ||
455 | return error; | 406 | sysfs_addrm_start(&acxt, dir_sd); |
407 | |||
408 | if (!sysfs_find_dirent(dir_sd, attr->name)) { | ||
409 | sysfs_add_one(&acxt, sd); | ||
410 | sysfs_link_sibling(sd); | ||
411 | } | ||
412 | |||
413 | if (sysfs_addrm_finish(&acxt)) | ||
414 | return 0; | ||
415 | |||
416 | sysfs_put(sd); | ||
417 | return -EEXIST; | ||
456 | } | 418 | } |
457 | 419 | ||
458 | 420 | ||
@@ -464,9 +426,9 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) | |||
464 | 426 | ||
465 | int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | 427 | int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) |
466 | { | 428 | { |
467 | BUG_ON(!kobj || !kobj->dentry || !attr); | 429 | BUG_ON(!kobj || !kobj->sd || !attr); |
468 | 430 | ||
469 | return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR); | 431 | return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); |
470 | 432 | ||
471 | } | 433 | } |
472 | 434 | ||
@@ -480,16 +442,16 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | |||
480 | int sysfs_add_file_to_group(struct kobject *kobj, | 442 | int sysfs_add_file_to_group(struct kobject *kobj, |
481 | const struct attribute *attr, const char *group) | 443 | const struct attribute *attr, const char *group) |
482 | { | 444 | { |
483 | struct dentry *dir; | 445 | struct sysfs_dirent *dir_sd; |
484 | int error; | 446 | int error; |
485 | 447 | ||
486 | dir = lookup_one_len(group, kobj->dentry, strlen(group)); | 448 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
487 | if (IS_ERR(dir)) | 449 | if (!dir_sd) |
488 | error = PTR_ERR(dir); | 450 | return -ENOENT; |
489 | else { | 451 | |
490 | error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR); | 452 | error = sysfs_add_file(dir_sd, attr, SYSFS_KOBJ_ATTR); |
491 | dput(dir); | 453 | sysfs_put(dir_sd); |
492 | } | 454 | |
493 | return error; | 455 | return error; |
494 | } | 456 | } |
495 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | 457 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); |
@@ -502,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
502 | */ | 464 | */ |
503 | int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | 465 | int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) |
504 | { | 466 | { |
505 | struct dentry * dir = kobj->dentry; | 467 | struct sysfs_dirent *victim_sd = NULL; |
506 | struct dentry * victim; | 468 | struct dentry *victim = NULL; |
507 | int res = -ENOENT; | 469 | int rc; |
508 | 470 | ||
509 | mutex_lock(&dir->d_inode->i_mutex); | 471 | rc = -ENOENT; |
510 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); | 472 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); |
511 | if (!IS_ERR(victim)) { | 473 | if (!victim_sd) |
512 | /* make sure dentry is really there */ | 474 | goto out; |
513 | if (victim->d_inode && | 475 | |
514 | (victim->d_parent->d_inode == dir->d_inode)) { | 476 | victim = sysfs_get_dentry(victim_sd); |
515 | victim->d_inode->i_mtime = CURRENT_TIME; | 477 | if (IS_ERR(victim)) { |
516 | fsnotify_modify(victim); | 478 | rc = PTR_ERR(victim); |
517 | res = 0; | 479 | victim = NULL; |
518 | } else | 480 | goto out; |
519 | d_drop(victim); | ||
520 | |||
521 | /** | ||
522 | * Drop the reference acquired from lookup_one_len() above. | ||
523 | */ | ||
524 | dput(victim); | ||
525 | } | 481 | } |
526 | mutex_unlock(&dir->d_inode->i_mutex); | ||
527 | 482 | ||
528 | return res; | 483 | mutex_lock(&victim->d_inode->i_mutex); |
484 | victim->d_inode->i_mtime = CURRENT_TIME; | ||
485 | fsnotify_modify(victim); | ||
486 | mutex_unlock(&victim->d_inode->i_mutex); | ||
487 | rc = 0; | ||
488 | out: | ||
489 | dput(victim); | ||
490 | sysfs_put(victim_sd); | ||
491 | return rc; | ||
529 | } | 492 | } |
530 | 493 | ||
531 | 494 | ||
@@ -538,30 +501,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | |||
538 | */ | 501 | */ |
539 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | 502 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) |
540 | { | 503 | { |
541 | struct dentry *dir = kobj->dentry; | 504 | struct sysfs_dirent *victim_sd = NULL; |
542 | struct dentry *victim; | 505 | struct dentry *victim = NULL; |
543 | struct inode * inode; | 506 | struct inode * inode; |
544 | struct iattr newattrs; | 507 | struct iattr newattrs; |
545 | int res = -ENOENT; | 508 | int rc; |
546 | 509 | ||
547 | mutex_lock(&dir->d_inode->i_mutex); | 510 | rc = -ENOENT; |
548 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); | 511 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); |
549 | if (!IS_ERR(victim)) { | 512 | if (!victim_sd) |
550 | if (victim->d_inode && | 513 | goto out; |
551 | (victim->d_parent->d_inode == dir->d_inode)) { | 514 | |
552 | inode = victim->d_inode; | 515 | victim = sysfs_get_dentry(victim_sd); |
553 | mutex_lock(&inode->i_mutex); | 516 | if (IS_ERR(victim)) { |
554 | newattrs.ia_mode = (mode & S_IALLUGO) | | 517 | rc = PTR_ERR(victim); |
555 | (inode->i_mode & ~S_IALLUGO); | 518 | victim = NULL; |
556 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 519 | goto out; |
557 | res = notify_change(victim, &newattrs); | ||
558 | mutex_unlock(&inode->i_mutex); | ||
559 | } | ||
560 | dput(victim); | ||
561 | } | 520 | } |
562 | mutex_unlock(&dir->d_inode->i_mutex); | ||
563 | 521 | ||
564 | return res; | 522 | inode = victim->d_inode; |
523 | mutex_lock(&inode->i_mutex); | ||
524 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | ||
525 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
526 | rc = notify_change(victim, &newattrs); | ||
527 | mutex_unlock(&inode->i_mutex); | ||
528 | out: | ||
529 | dput(victim); | ||
530 | sysfs_put(victim_sd); | ||
531 | return rc; | ||
565 | } | 532 | } |
566 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 533 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
567 | 534 | ||
@@ -576,7 +543,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
576 | 543 | ||
577 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | 544 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) |
578 | { | 545 | { |
579 | sysfs_hash_and_remove(kobj->dentry, attr->name); | 546 | sysfs_hash_and_remove(kobj->sd, attr->name); |
580 | } | 547 | } |
581 | 548 | ||
582 | 549 | ||
@@ -589,12 +556,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | |||
589 | void sysfs_remove_file_from_group(struct kobject *kobj, | 556 | void sysfs_remove_file_from_group(struct kobject *kobj, |
590 | const struct attribute *attr, const char *group) | 557 | const struct attribute *attr, const char *group) |
591 | { | 558 | { |
592 | struct dentry *dir; | 559 | struct sysfs_dirent *dir_sd; |
593 | 560 | ||
594 | dir = lookup_one_len(group, kobj->dentry, strlen(group)); | 561 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
595 | if (!IS_ERR(dir)) { | 562 | if (dir_sd) { |
596 | sysfs_hash_and_remove(dir, attr->name); | 563 | sysfs_hash_and_remove(dir_sd, attr->name); |
597 | dput(dir); | 564 | sysfs_put(dir_sd); |
598 | } | 565 | } |
599 | } | 566 | } |
600 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); | 567 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); |