aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c379
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/** 53struct 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;
59static inline void 59 int needs_read_fill;
60add_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
69static inline void
70remove_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 */
88static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) 74static 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
199static int 188static int
200flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) 189flush_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;
243out:
244 up(&buffer->sem); 237 up(&buffer->sem);
245 return len; 238 return len;
246} 239}
247 240
248static int sysfs_open_file(struct inode *inode, struct file *file) 241static 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
341static int sysfs_release(struct inode * inode, struct file * filp) 312static 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)
376static unsigned int sysfs_poll(struct file *filp, poll_table *wait) 341static 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
394static 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
414void sysfs_notify(struct kobject * k, char *dir, char *attr) 365void 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}
431EXPORT_SYMBOL_GPL(sysfs_notify); 382EXPORT_SYMBOL_GPL(sysfs_notify);
432 383
@@ -440,19 +391,30 @@ const struct file_operations sysfs_file_operations = {
440}; 391};
441 392
442 393
443int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) 394int 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
465int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) 427int 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)
480int sysfs_add_file_to_group(struct kobject *kobj, 442int 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}
495EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); 457EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
@@ -502,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
502 */ 464 */
503int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) 465int 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 */
539int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) 502int 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}
566EXPORT_SYMBOL_GPL(sysfs_chmod_file); 533EXPORT_SYMBOL_GPL(sysfs_chmod_file);
567 534
@@ -576,7 +543,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
576 543
577void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) 544void 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)
589void sysfs_remove_file_from_group(struct kobject *kobj, 556void 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}
600EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); 567EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);