@@ -508,7 +508,6 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
struct ceph_snap_context *snapc;
struct ceph_vino vino;
struct ceph_osd_request *req;
- int num_ops = 1;
struct page **pages;
int num_pages;
u64 len;
@@ -516,9 +515,10 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
int flags;
int check_caps = 0;
int page_align;
- int ret, i;
+ int ret;
struct timespec mtime = CURRENT_TIME;
loff_t pos = iocb->ki_pos;
+ struct iov_iter i;
if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
return -EROFS;
@@ -539,21 +539,20 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
flags = CEPH_OSD_FLAG_ORDERSNAP |
CEPH_OSD_FLAG_ONDISK |
CEPH_OSD_FLAG_WRITE;
- num_ops++; /* Also include a 'startsync' command. */
- for (i = 0; i < nr_segs && count; i++) {
- void __user *data = iov[i].iov_base;
- size_t left;
+ iov_iter_init(&i, iov, nr_segs, count, 0);
+
+ for (iov_iter_count(&i) > 0) {
+ void __user *data = i.iov->iov_base + i.iov_offset;
+ u64 len = i.iov->iov_len - i.iov_offset;
- left = min(count, iov[i].iov_len);
-more:
page_align = (unsigned long)data & ~PAGE_MASK;
- len = left;
snapc = ci->i_snap_realm->cached_context;
vino = ceph_vino(inode);
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
- vino, pos, &len, num_ops,
+ vino, pos, &len,
+ 2, /* include a 'startsync' command */
CEPH_OSD_OP_WRITE, flags, snapc,
ci->i_truncate_seq,
ci->i_truncate_size,
@@ -593,13 +592,8 @@ out:
if (ret == 0) {
pos += len;
written += len;
- left -= len;
- count -= len;
- data += len;
- if (left)
- goto more;
+ iov_iter_advance(&i, (size_t)len);
- ret = written;
if (pos > i_size_read(inode))
check_caps = ceph_inode_set_size(inode, pos);
if (check_caps)
@@ -607,14 +601,14 @@ out:
CHECK_CAPS_AUTHONLY,
NULL);
} else {
- if (ret != -EOLDSNAPC && written > 0)
- ret = written;
break;
}
}
- if (ret > 0)
+ if (ret != -EOLDSNAPC && written > 0) {
iocb->ki_pos = pos;
+ ret = written;
+ }
return ret;
}
@@ -636,10 +630,9 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
struct ceph_snap_context *snapc;
struct ceph_vino vino;
struct ceph_osd_request *req;
- int num_ops = 1;
struct page **pages;
- int num_pages;
u64 len;
+ int num_pages;
int written = 0;
int flags;
int check_caps = 0;
@@ -670,18 +663,14 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
iov_iter_init(&i, iov, nr_segs, count, 0);
- while (i.count) {
- void __user *data;
+ while ((len = iov_iter_count(&i)) > 0) {
size_t left;
-
- left = i.count;
-more:
- len = left;
+ int n;
snapc = ci->i_snap_realm->cached_context;
vino = ceph_vino(inode);
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
- vino, pos, &len, num_ops,
+ vino, pos, &len, 1,
CEPH_OSD_OP_WRITE, flags, snapc,
ci->i_truncate_seq,
ci->i_truncate_size,
@@ -702,42 +691,17 @@ more:
ret = PTR_ERR(pages);
goto out;
}
- if (len <= i.iov[0].iov_len - i.iov_offset) {
- data = i.iov[0].iov_base + i.iov_offset;
- ret = ceph_copy_user_to_page_vector(pages,
- data, 0, len);
- if (ret > 0)
- iov_iter_advance(&i, ret);
- } else {
- int l, k = 0, copyed = 0;
- size_t tmp = len;
-
- while (tmp) {
- data = i.iov[0].iov_base + i.iov_offset;
- l = i.iov[0].iov_len - i.iov_offset;
-
- if (tmp < l) {
- ret = ceph_copy_user_to_page_vector(&pages[k],
- data,
- copyed,
- tmp);
- if (ret > 0)
- iov_iter_advance(&i, ret);
- break;
- } else if (l) {
- ret = ceph_copy_user_to_page_vector(&pages[k],
- data,
- copyed,
- l);
- if (ret < 0)
- break;
- iov_iter_advance(&i, ret);
- copyed += ret;
- tmp -= ret;
- k = calc_pages_for(0, copyed + 1) - 1;
- }
+ left = len;
+ for (n = 0; n < num_pages; n++) {
+ size_t plen = min(left, PAGE_SIZE);
+ ret = iov_iter_copy_from_user(pages[n], &i, 0, l);
+ if (ret != plen) {
+ ret = -EFAULT;
+ break;
}
+ left -= ret;
+ iov_iter_advance(&i, ret);
}
if (ret < 0) {
@@ -764,26 +728,23 @@ out:
if (ret == 0) {
pos += len;
written += len;
- left -= len;
- if (left)
- goto more;
- ret = written;
- if (pos > i_size_read(inode))
+ if (pos > i_size_read(inode)) {
check_caps = ceph_inode_set_size(inode, pos);
if (check_caps)
ceph_check_caps(ceph_inode(inode),
CHECK_CAPS_AUTHONLY,
NULL);
+ }
} else {
- if (ret != -EOLDSNAPC && written > 0)
- ret = written;
break;
}
}
- if (ret > 0)
+ if (ret != -EOLDSNAPC && written > 0) {
+ ret = written;
iocb->ki_pos = pos;
+ }
return ret;
}