diff options
Diffstat (limited to 'fs/libfs.c')
| -rw-r--r-- | fs/libfs.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index f90b29595927..5025563e7379 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -519,6 +519,102 @@ int simple_transaction_release(struct inode *inode, struct file *file) | |||
| 519 | return 0; | 519 | return 0; |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | /* Simple attribute files */ | ||
| 523 | |||
| 524 | struct simple_attr { | ||
| 525 | u64 (*get)(void *); | ||
| 526 | void (*set)(void *, u64); | ||
| 527 | char get_buf[24]; /* enough to store a u64 and "\n\0" */ | ||
| 528 | char set_buf[24]; | ||
| 529 | void *data; | ||
| 530 | const char *fmt; /* format for read operation */ | ||
| 531 | struct semaphore sem; /* protects access to these buffers */ | ||
| 532 | }; | ||
| 533 | |||
| 534 | /* simple_attr_open is called by an actual attribute open file operation | ||
| 535 | * to set the attribute specific access operations. */ | ||
| 536 | int simple_attr_open(struct inode *inode, struct file *file, | ||
| 537 | u64 (*get)(void *), void (*set)(void *, u64), | ||
| 538 | const char *fmt) | ||
| 539 | { | ||
| 540 | struct simple_attr *attr; | ||
| 541 | |||
| 542 | attr = kmalloc(sizeof(*attr), GFP_KERNEL); | ||
| 543 | if (!attr) | ||
| 544 | return -ENOMEM; | ||
| 545 | |||
| 546 | attr->get = get; | ||
| 547 | attr->set = set; | ||
| 548 | attr->data = inode->u.generic_ip; | ||
| 549 | attr->fmt = fmt; | ||
| 550 | init_MUTEX(&attr->sem); | ||
| 551 | |||
| 552 | file->private_data = attr; | ||
| 553 | |||
| 554 | return nonseekable_open(inode, file); | ||
| 555 | } | ||
| 556 | |||
| 557 | int simple_attr_close(struct inode *inode, struct file *file) | ||
| 558 | { | ||
| 559 | kfree(file->private_data); | ||
| 560 | return 0; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* read from the buffer that is filled with the get function */ | ||
| 564 | ssize_t simple_attr_read(struct file *file, char __user *buf, | ||
| 565 | size_t len, loff_t *ppos) | ||
| 566 | { | ||
| 567 | struct simple_attr *attr; | ||
| 568 | size_t size; | ||
| 569 | ssize_t ret; | ||
| 570 | |||
| 571 | attr = file->private_data; | ||
| 572 | |||
| 573 | if (!attr->get) | ||
| 574 | return -EACCES; | ||
| 575 | |||
| 576 | down(&attr->sem); | ||
| 577 | if (*ppos) /* continued read */ | ||
| 578 | size = strlen(attr->get_buf); | ||
| 579 | else /* first read */ | ||
| 580 | size = scnprintf(attr->get_buf, sizeof(attr->get_buf), | ||
| 581 | attr->fmt, | ||
| 582 | (unsigned long long)attr->get(attr->data)); | ||
| 583 | |||
| 584 | ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); | ||
| 585 | up(&attr->sem); | ||
| 586 | return ret; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* interpret the buffer as a number to call the set function with */ | ||
| 590 | ssize_t simple_attr_write(struct file *file, const char __user *buf, | ||
| 591 | size_t len, loff_t *ppos) | ||
| 592 | { | ||
| 593 | struct simple_attr *attr; | ||
| 594 | u64 val; | ||
| 595 | size_t size; | ||
| 596 | ssize_t ret; | ||
| 597 | |||
| 598 | attr = file->private_data; | ||
| 599 | |||
| 600 | if (!attr->set) | ||
| 601 | return -EACCES; | ||
| 602 | |||
| 603 | down(&attr->sem); | ||
| 604 | ret = -EFAULT; | ||
| 605 | size = min(sizeof(attr->set_buf) - 1, len); | ||
| 606 | if (copy_from_user(attr->set_buf, buf, size)) | ||
| 607 | goto out; | ||
| 608 | |||
| 609 | ret = len; /* claim we got the whole input */ | ||
| 610 | attr->set_buf[size] = '\0'; | ||
| 611 | val = simple_strtol(attr->set_buf, NULL, 0); | ||
| 612 | attr->set(attr->data, val); | ||
| 613 | out: | ||
| 614 | up(&attr->sem); | ||
| 615 | return ret; | ||
| 616 | } | ||
| 617 | |||
| 522 | EXPORT_SYMBOL(dcache_dir_close); | 618 | EXPORT_SYMBOL(dcache_dir_close); |
| 523 | EXPORT_SYMBOL(dcache_dir_lseek); | 619 | EXPORT_SYMBOL(dcache_dir_lseek); |
| 524 | EXPORT_SYMBOL(dcache_dir_open); | 620 | EXPORT_SYMBOL(dcache_dir_open); |
| @@ -547,3 +643,7 @@ EXPORT_SYMBOL(simple_read_from_buffer); | |||
| 547 | EXPORT_SYMBOL(simple_transaction_get); | 643 | EXPORT_SYMBOL(simple_transaction_get); |
| 548 | EXPORT_SYMBOL(simple_transaction_read); | 644 | EXPORT_SYMBOL(simple_transaction_read); |
| 549 | EXPORT_SYMBOL(simple_transaction_release); | 645 | EXPORT_SYMBOL(simple_transaction_release); |
| 646 | EXPORT_SYMBOL_GPL(simple_attr_open); | ||
| 647 | EXPORT_SYMBOL_GPL(simple_attr_close); | ||
| 648 | EXPORT_SYMBOL_GPL(simple_attr_read); | ||
| 649 | EXPORT_SYMBOL_GPL(simple_attr_write); | ||
