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