static int open(struct inode * inode, struct file * file) { struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent); struct bin_attribute * attr = to_bin_attr(file->f_dentry); int error = -EINVAL; if (!kobj || !attr) goto Done; /* Grab the module reference for this attribute if we have one */ error = -ENODEV; if (!try_module_get(attr->attr.owner)) goto Done; error = -EACCES; if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) goto Error; if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) goto Error; error = -ENOMEM; file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!file->private_data) goto Error; error = 0; goto Done; Error: module_put(attr->attr.owner); Done: if (error && kobj) kobject_put(kobj); return error; }
static int configfs_release_bin_file(struct inode *inode, struct file *filp) { struct configfs_buffer *buffer = filp->private_data; struct dentry *dentry = filp->f_path.dentry; struct config_item *item = to_item(dentry->d_parent); struct configfs_item_operations *ops = buffer->ops; struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); ssize_t len = 0; int ret; buffer->read_in_progress = 0; if (buffer->write_in_progress) { buffer->write_in_progress = 0; len = ops->write_bin_attribute(item, bin_attr, buffer->bin_buffer, buffer->bin_buffer_size); /* vfree on NULL is safe */ vfree(buffer->bin_buffer); buffer->bin_buffer = NULL; buffer->bin_buffer_size = 0; buffer->needs_read_fill = 1; } ret = do_release(inode, filp, to_item(filp->f_path.dentry->d_parent), to_attr(filp->f_path.dentry), CONFIGFS_ITEM_BIN_ATTR); if (len < 0) return len; return ret; }
static ssize_t configfs_read_bin_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct configfs_buffer *buffer = file->private_data; struct dentry *dentry = file->f_path.dentry; struct config_item *item = to_item(dentry->d_parent); struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); ssize_t retval = 0; ssize_t len = min_t(size_t, count, PAGE_SIZE); mutex_lock(&buffer->mutex); /* we don't support switching read/write modes */ if (buffer->write_in_progress) { retval = -ETXTBSY; goto out; } buffer->read_in_progress = 1; if (buffer->needs_read_fill) { /* perform first read with buf == NULL to get extent */ len = bin_attr->read(item, NULL, 0); if (len <= 0) { retval = len; goto out; } /* do not exceed the maximum value */ if (bin_attr->cb_max_size && len > bin_attr->cb_max_size) { retval = -EFBIG; goto out; } buffer->bin_buffer = vmalloc(len); if (buffer->bin_buffer == NULL) { retval = -ENOMEM; goto out; } buffer->bin_buffer_size = len; /* perform second read to fill buffer */ len = bin_attr->read(item, buffer->bin_buffer, len); if (len < 0) { retval = len; vfree(buffer->bin_buffer); buffer->bin_buffer_size = 0; buffer->bin_buffer = NULL; goto out; } buffer->needs_read_fill = 0; } retval = simple_read_from_buffer(buf, count, ppos, buffer->bin_buffer, buffer->bin_buffer_size); out: mutex_unlock(&buffer->mutex); return retval; }
static ssize_t configfs_write_bin_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct configfs_buffer *buffer = file->private_data; struct dentry *dentry = file->f_path.dentry; struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); void *tbuf = NULL; ssize_t len; mutex_lock(&buffer->mutex); /* we don't support switching read/write modes */ if (buffer->read_in_progress) { len = -ETXTBSY; goto out; } buffer->write_in_progress = 1; /* buffer grows? */ if (*ppos + count > buffer->bin_buffer_size) { if (bin_attr->cb_max_size && *ppos + count > bin_attr->cb_max_size) { len = -EFBIG; } tbuf = vmalloc(*ppos + count); if (tbuf == NULL) { len = -ENOMEM; goto out; } /* copy old contents */ if (buffer->bin_buffer) { memcpy(tbuf, buffer->bin_buffer, buffer->bin_buffer_size); vfree(buffer->bin_buffer); } /* clear the new area */ memset(tbuf + buffer->bin_buffer_size, 0, *ppos + count - buffer->bin_buffer_size); buffer->bin_buffer = tbuf; buffer->bin_buffer_size = *ppos + count; } len = simple_write_to_buffer(buffer->bin_buffer, buffer->bin_buffer_size, ppos, buf, count); if (len > 0) *ppos += len; out: mutex_unlock(&buffer->mutex); return len; }
static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { struct bin_attribute *attr = to_bin_attr(dentry); struct kobject *kobj = to_kobj(dentry->d_parent); if (!attr->write) return -EIO; return attr->write(kobj, buffer, offset, count); }
static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { struct bin_attribute * attr = to_bin_attr(dentry); struct kobject * kobj = to_kobj(dentry->d_parent); if (!attr->read) return -EIO; return attr->read(kobj, buffer, off, count); }
static int mmap(struct file *file, struct vm_area_struct *vma) { struct dentry *dentry = file->f_dentry; struct bin_attribute *attr = to_bin_attr(dentry); struct kobject *kobj = to_kobj(dentry->d_parent); if (!attr->mmap) return -EINVAL; return attr->mmap(kobj, attr, vma); }
static int release(struct inode * inode, struct file * file) { struct kobject * kobj = to_kobj(file->f_dentry->d_parent); struct bin_attribute * attr = to_bin_attr(file->f_dentry); u8 * buffer = file->private_data; if (kobj) kobject_put(kobj); module_put(attr->attr.owner); kfree(buffer); return 0; }
static int check_perm(struct inode * inode, struct file * file, int type) { struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent); struct configfs_attribute * attr = to_attr(file->f_path.dentry); struct configfs_bin_attribute *bin_attr = NULL; struct configfs_buffer * buffer; struct configfs_item_operations * ops = NULL; int error = 0; if (!item || !attr) goto Einval; if (type & CONFIGFS_ITEM_BIN_ATTR) bin_attr = to_bin_attr(file->f_path.dentry); /* Grab the module reference for this attribute if we have one */ if (!try_module_get(attr->ca_owner)) { error = -ENODEV; goto Done; } if (item->ci_type) ops = item->ci_type->ct_item_ops; else goto Eaccess; /* File needs write support. * The inode's perms must say it's ok, * and we must have a store method. */ if (file->f_mode & FMODE_WRITE) { if (!(inode->i_mode & S_IWUGO)) goto Eaccess; if ((type & CONFIGFS_ITEM_ATTR) && !attr->store) goto Eaccess; if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->write) goto Eaccess; } /* File needs read support. * The inode's perms must say it's ok, and we there * must be a show method for it. */ if (file->f_mode & FMODE_READ) { if (!(inode->i_mode & S_IRUGO)) goto Eaccess; if ((type & CONFIGFS_ITEM_ATTR) && !attr->show) goto Eaccess; if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->read) goto Eaccess; } /* No error? Great, allocate a buffer for the file, and store it * it in file->private_data for easy access. */ buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL); if (!buffer) { error = -ENOMEM; goto Enomem; } mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->read_in_progress = 0; buffer->write_in_progress = 0; buffer->ops = ops; file->private_data = buffer; goto Done; Einval: error = -EINVAL; goto Done; Eaccess: error = -EACCES; Enomem: module_put(attr->ca_owner); Done: if (error && item) config_item_put(item); return error; }