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; }
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; }