static ssize_t hv_cdev_write(struct file *filp,
	const char __user *ubuff, size_t count, loff_t *f_pos)
{
	int n = 0;
	hv_cdev_private *priv = filp->private_data;

	PINFO("%s:\n", __func__);

	PDEBUG("ubuf=%p, count=%zu, f_pos=%lld, priv->dev_size=%llu\n",
				ubuff, count, *f_pos, priv->dev_size);

	if (mutex_lock_interruptible(&priv->cmutex)) {
		PERR("%s: Failed to acquire cmutex\n", __func__);
		return -ERESTARTSYS;
	}

	/* Check if file position over the disksize */
	if (*f_pos >= priv->dev_size) {
		PERR("file position exceeds disk size");
		goto out;
	}

	/* Trim if total req. read bytes over disk size */
	if ((*f_pos + count) > priv->dev_size)
		count = priv->dev_size - *f_pos;

	/* Copy from user buffer to kernel buff */
	if (use_static_buff) {
		if (__copy_from_user_nocache(priv->buff + *f_pos, ubuff, count)) {
			n = -EFAULT;
			PERR("Error: Copy_from_user failed\n");
			goto out;
		}
	} else {
		if (__copy_from_user_nocache(priv->mmls_iomem + *f_pos, ubuff, count)) {
			n = -EFAULT;
			PERR("Error: Copy_from_user failed\n");
			goto out;
		}
		mmls_write_command(1, count/512, (*f_pos)/512, (unsigned long)priv->mmls_iomem, 0, NULL);
	}

	*f_pos += count;
	n = count;

out:
	mutex_unlock(&priv->cmutex);

	return n;
}
Beispiel #2
0
static ssize_t __hmfs_xip_file_write(struct file *filp, const char __user * buf,
				     size_t count, loff_t pos, loff_t * ppos)
{
	struct inode *inode = filp->f_inode;
	long status = 0;
	size_t bytes;
	ssize_t written = 0;

	//FIXME: file inode lock
	do {
		unsigned long index;
		unsigned long offset;
		size_t copied;
		void *xip_mem;

		offset = pos & ~HMFS_PAGE_MASK;
		index = pos >> HMFS_PAGE_SIZE_BITS;
		bytes = HMFS_PAGE_SIZE - offset;
		if (bytes > count)
			bytes = count;

		xip_mem = alloc_new_data_block(inode, index);
		if (unlikely(IS_ERR(xip_mem)))
			break;

		copied =
		 bytes - __copy_from_user_nocache(xip_mem + offset, buf, bytes);

		if (likely(copied > 0)) {
			status = copied;

			if (status >= 0) {
				written += status;
				count -= status;
				pos += status;
				buf += status;
			}
		}
		if (unlikely(copied != bytes))
			if (status >= 0)
				status = -EFAULT;
		if (status < 0)
			break;
	} while (count);
	*ppos = pos;

	if (pos > inode->i_size) {
		mark_size_dirty(inode, pos);
	}
	return written ? written : status;

}
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
{
	char *to = addr;
	if (unlikely(bytes > i->count))
		bytes = i->count;

	if (unlikely(!bytes))
		return 0;

	iterate_and_advance(i, bytes, v,
		__copy_from_user_nocache((to += v.iov_len) - v.iov_len,
					 v.iov_base, v.iov_len),
		memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
				 v.bv_offset, v.bv_len),
		memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
	)

	return bytes;
}