Ejemplo n.º 1
0
/**
 * sysfs_write_file - write an attribute
 * @file: file pointer
 * @user_buf: data to write
 * @count: number of bytes
 * @ppos: starting offset
 *
 * Copy data in from userland and pass it to the matching
 * sysfs_ops->store() by invoking flush_write_buffer().
 *
 * There is no easy way for us to know if userspace is only doing a partial
 * write, so we don't support them. We expect the entire buffer to come on
 * the first write.  Hint: if you're writing a value, first read the file,
 * modify only the the value you're changing, then write entire buffer
 * back.
 */
static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf,
				size_t count, loff_t *ppos)
{
	struct sysfs_open_file *of = sysfs_of(file);
	ssize_t len = min_t(size_t, count, PAGE_SIZE);
	loff_t size = file_inode(file)->i_size;
	char *buf;

	if (sysfs_is_bin(of->sd) && size) {
		if (size <= *ppos)
			return 0;
		len = min_t(ssize_t, len, size - *ppos);
	}

	if (!len)
		return 0;

	buf = kmalloc(len + 1, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	if (copy_from_user(buf, user_buf, len)) {
		len = -EFAULT;
		goto out_free;
	}
	buf[len] = '\0';	/* guarantee string termination */

	len = flush_write_buffer(of, buf, *ppos, len);
	if (len > 0)
		*ppos += len;
out_free:
	kfree(buf);
	return len;
}
Ejemplo n.º 2
0
/*
 * Read method for bin files.  As reading a bin file can have side-effects,
 * the exact offset and bytes specified in read(2) call should be passed to
 * the read callback making it difficult to use seq_file.  Implement
 * simplistic custom buffering for bin files.
 */
static ssize_t sysfs_bin_read(struct file *file, char __user *userbuf,
			      size_t bytes, loff_t *off)
{
	struct sysfs_open_file *of = sysfs_of(file);
	struct bin_attribute *battr = of->sd->s_attr.bin_attr;
	struct kobject *kobj = of->sd->s_parent->s_dir.kobj;
	loff_t size = file_inode(file)->i_size;
	int count = min_t(size_t, bytes, PAGE_SIZE);
	loff_t offs = *off;
	char *buf;

	if (!bytes)
		return 0;

	if (size) {
		if (offs > size)
			return 0;
		if (offs + count > size)
			count = size - offs;
	}

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/* need of->sd for battr, its parent for kobj */
	mutex_lock(&of->mutex);
	if (!sysfs_get_active(of->sd)) {
		count = -ENODEV;
		mutex_unlock(&of->mutex);
		goto out_free;
	}

	if (battr->read)
		count = battr->read(file, kobj, battr, buf, offs, count);
	else
		count = -EIO;

	sysfs_put_active(of->sd);
	mutex_unlock(&of->mutex);

	if (count < 0)
		goto out_free;

	if (copy_to_user(userbuf, buf, count)) {
		count = -EFAULT;
		goto out_free;
	}

	pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);

	*off = offs + count;

 out_free:
	kfree(buf);
	return count;
}
Ejemplo n.º 3
0
static void sysfs_bin_vma_open(struct vm_area_struct *vma)
{
	struct file *file = vma->vm_file;
	struct sysfs_open_file *of = sysfs_of(file);

	if (!of->vm_ops)
		return;

	if (!sysfs_get_active(of->sd))
		return;

	if (of->vm_ops->open)
		of->vm_ops->open(vma);

	sysfs_put_active(of->sd);
}
Ejemplo n.º 4
0
static int sysfs_bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
	struct file *file = vma->vm_file;
	struct sysfs_open_file *of = sysfs_of(file);
	int ret;

	if (!of->vm_ops)
		return VM_FAULT_SIGBUS;

	if (!sysfs_get_active(of->sd))
		return VM_FAULT_SIGBUS;

	ret = VM_FAULT_SIGBUS;
	if (of->vm_ops->fault)
		ret = of->vm_ops->fault(vma, vmf);

	sysfs_put_active(of->sd);
	return ret;
}
Ejemplo n.º 5
0
static int sysfs_bin_access(struct vm_area_struct *vma, unsigned long addr,
			    void *buf, int len, int write)
{
	struct file *file = vma->vm_file;
	struct sysfs_open_file *of = sysfs_of(file);
	int ret;

	if (!of->vm_ops)
		return -EINVAL;

	if (!sysfs_get_active(of->sd))
		return -EINVAL;

	ret = -EINVAL;
	if (of->vm_ops->access)
		ret = of->vm_ops->access(vma, addr, buf, len, write);

	sysfs_put_active(of->sd);
	return ret;
}
Ejemplo n.º 6
0
static int sysfs_bin_page_mkwrite(struct vm_area_struct *vma,
				  struct vm_fault *vmf)
{
	struct file *file = vma->vm_file;
	struct sysfs_open_file *of = sysfs_of(file);
	int ret;

	if (!of->vm_ops)
		return VM_FAULT_SIGBUS;

	if (!sysfs_get_active(of->sd))
		return VM_FAULT_SIGBUS;

	ret = 0;
	if (of->vm_ops->page_mkwrite)
		ret = of->vm_ops->page_mkwrite(vma, vmf);
	else
		file_update_time(file);

	sysfs_put_active(of->sd);
	return ret;
}
Ejemplo n.º 7
0
		return -EINVAL;

	ret = -EINVAL;
	if (of->vm_ops->access)
		ret = of->vm_ops->access(vma, addr, buf, len, write);

	sysfs_put_active(of->sd);
	return ret;
}

#ifdef CONFIG_NUMA
static int sysfs_bin_set_policy(struct vm_area_struct *vma,
				struct mempolicy *new)
{
	struct file *file = vma->vm_file;
	struct sysfs_open_file *of = sysfs_of(file);
	int ret;

	if (!of->vm_ops)
		return 0;

	if (!sysfs_get_active(of->sd))
		return -EINVAL;

	ret = 0;
	if (of->vm_ops->set_policy)
		ret = of->vm_ops->set_policy(vma, new);

	sysfs_put_active(of->sd);
	return ret;
}