diff options
author | Tony Luck <tony.luck@intel.com> | 2005-06-21 16:21:20 -0700 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-06-21 16:21:20 -0700 |
commit | 29516d75a0b09e0a0328dd55c98a342515c9615a (patch) | |
tree | 4b03326311958ad6de82653a1caf289ad8c38538 /fs/libfs.c | |
parent | 4ea78729b8dbfc400fe165a57b90a394a7275a54 (diff) | |
parent | 4a4f8fdba6f5a34ca90f426021e17491a30202da (diff) | |
download | linux-29516d75a0b09e0a0328dd55c98a342515c9615a.tar.gz linux-29516d75a0b09e0a0328dd55c98a342515c9615a.tar.bz2 linux-29516d75a0b09e0a0328dd55c98a342515c9615a.zip |
Auto merge with /home/aegl/GIT/linus
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) return 0; } +/* Simple attribute files */ + +struct simple_attr { + u64 (*get)(void *); + void (*set)(void *, u64); + char get_buf[24]; /* enough to store a u64 and "\n\0" */ + char set_buf[24]; + void *data; + const char *fmt; /* format for read operation */ + struct semaphore sem; /* protects access to these buffers */ +}; + +/* simple_attr_open is called by an actual attribute open file operation + * to set the attribute specific access operations. */ +int simple_attr_open(struct inode *inode, struct file *file, + u64 (*get)(void *), void (*set)(void *, u64), + const char *fmt) +{ + struct simple_attr *attr; + + attr = kmalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->get = get; + attr->set = set; + attr->data = inode->u.generic_ip; + attr->fmt = fmt; + init_MUTEX(&attr->sem); + + file->private_data = attr; + + return nonseekable_open(inode, file); +} + +int simple_attr_close(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +/* read from the buffer that is filled with the get function */ +ssize_t simple_attr_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + struct simple_attr *attr; + size_t size; + ssize_t ret; + + attr = file->private_data; + + if (!attr->get) + return -EACCES; + + down(&attr->sem); + if (*ppos) /* continued read */ + size = strlen(attr->get_buf); + else /* first read */ + size = scnprintf(attr->get_buf, sizeof(attr->get_buf), + attr->fmt, + (unsigned long long)attr->get(attr->data)); + + ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); + up(&attr->sem); + return ret; +} + +/* interpret the buffer as a number to call the set function with */ +ssize_t simple_attr_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct simple_attr *attr; + u64 val; + size_t size; + ssize_t ret; + + attr = file->private_data; + + if (!attr->set) + return -EACCES; + + down(&attr->sem); + ret = -EFAULT; + size = min(sizeof(attr->set_buf) - 1, len); + if (copy_from_user(attr->set_buf, buf, size)) + goto out; + + ret = len; /* claim we got the whole input */ + attr->set_buf[size] = '\0'; + val = simple_strtol(attr->set_buf, NULL, 0); + attr->set(attr->data, val); +out: + up(&attr->sem); + return ret; +} + EXPORT_SYMBOL(dcache_dir_close); EXPORT_SYMBOL(dcache_dir_lseek); EXPORT_SYMBOL(dcache_dir_open); @@ -547,3 +643,7 @@ EXPORT_SYMBOL(simple_read_from_buffer); EXPORT_SYMBOL(simple_transaction_get); EXPORT_SYMBOL(simple_transaction_read); EXPORT_SYMBOL(simple_transaction_release); +EXPORT_SYMBOL_GPL(simple_attr_open); +EXPORT_SYMBOL_GPL(simple_attr_close); +EXPORT_SYMBOL_GPL(simple_attr_read); +EXPORT_SYMBOL_GPL(simple_attr_write); |