#include <linux/fs.h>
#include "internal.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/unistd.h>
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
}
EXPORT_SYMBOL(__vfs_write);
+vfs_readf_t vfs_readf(struct file *file)
+{
+ const struct file_operations *fop = file->f_op;
+
+ if (fop->read)
+ return fop->read;
+ if (fop->read_iter)
+ return new_sync_read;
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(vfs_readf);
+
+vfs_writef_t vfs_writef(struct file *file)
+{
+ const struct file_operations *fop = file->f_op;
+
+ if (fop->write)
+ return fop->write;
+ if (fop->write_iter)
+ return new_sync_write;
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(vfs_writef);
+
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
{
mm_segment_t old_fs;
* Check that the two inodes are eligible for cloning, the ranges make
* sense, and then flush all dirty data. Caller must ensure that the
* inodes have been locked against any other modifications.
+ *
+ * Returns: 0 for "nothing to clone", 1 for "something to clone", or
+ * the usual negative error code.
*/
int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
struct inode *inode_out, loff_t pos_out,
/* Are we going all the way to the end? */
isize = i_size_read(inode_in);
- if (isize == 0) {
- *len = 0;
+ if (isize == 0)
return 0;
- }
/* Zero length dedupe exits immediately; reflink goes to EOF. */
if (*len == 0) {
- if (is_dedupe) {
- *len = 0;
+ if (is_dedupe || pos_in == isize)
return 0;
- }
+ if (pos_in > isize)
+ return -EINVAL;
*len = isize - pos_in;
}
return -EBADE;
}
- return 0;
+ return 1;
}
EXPORT_SYMBOL(vfs_clone_file_prep_inodes);
goto out;
ret = 0;
+ if (off + len > i_size_read(src))
+ return -EINVAL;
+
/* pre-format output fields to sane values */
for (i = 0; i < count; i++) {
same->info[i].bytes_deduped = 0ULL;