diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-05-08 20:47:32 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-07-10 20:31:46 -0400 |
commit | 3a307ffc2730bfa1a4dfa94537be9d412338aad2 (patch) | |
tree | 3e83201eb816aec8b897afcf3920dd716ce4412c /fs/ocfs2/file.c | |
parent | 2e89b2e48e1da09ed483f195968c9172aa95b5e2 (diff) |
ocfs2: rework ocfs2_buffered_write_cluster()
Use some ideas from the new-aops patch series and turn
ocfs2_buffered_write_cluster() into a 2 stage operation with the caller
copying data in between. The code now understands multiple cluster writes as
a result of having to deal with a full page write for greater than 4k pages.
This sets us up to easily call into the write path during ->page_mkwrite().
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 121 |
1 files changed, 67 insertions, 54 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 566f9b70ec91..4c850d00c269 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -1335,15 +1335,16 @@ ocfs2_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes) | |||
1335 | *basep = base; | 1335 | *basep = base; |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | static struct page * ocfs2_get_write_source(struct ocfs2_buffered_write_priv *bp, | 1338 | static struct page * ocfs2_get_write_source(char **ret_src_buf, |
1339 | const struct iovec *cur_iov, | 1339 | const struct iovec *cur_iov, |
1340 | size_t iov_offset) | 1340 | size_t iov_offset) |
1341 | { | 1341 | { |
1342 | int ret; | 1342 | int ret; |
1343 | char *buf; | 1343 | char *buf = cur_iov->iov_base + iov_offset; |
1344 | struct page *src_page = NULL; | 1344 | struct page *src_page = NULL; |
1345 | unsigned long off; | ||
1345 | 1346 | ||
1346 | buf = cur_iov->iov_base + iov_offset; | 1347 | off = (unsigned long)(buf) & ~PAGE_CACHE_MASK; |
1347 | 1348 | ||
1348 | if (!segment_eq(get_fs(), KERNEL_DS)) { | 1349 | if (!segment_eq(get_fs(), KERNEL_DS)) { |
1349 | /* | 1350 | /* |
@@ -1355,18 +1356,17 @@ static struct page * ocfs2_get_write_source(struct ocfs2_buffered_write_priv *bp | |||
1355 | (unsigned long)buf & PAGE_CACHE_MASK, 1, | 1356 | (unsigned long)buf & PAGE_CACHE_MASK, 1, |
1356 | 0, 0, &src_page, NULL); | 1357 | 0, 0, &src_page, NULL); |
1357 | if (ret == 1) | 1358 | if (ret == 1) |
1358 | bp->b_src_buf = kmap(src_page); | 1359 | *ret_src_buf = kmap(src_page) + off; |
1359 | else | 1360 | else |
1360 | src_page = ERR_PTR(-EFAULT); | 1361 | src_page = ERR_PTR(-EFAULT); |
1361 | } else { | 1362 | } else { |
1362 | bp->b_src_buf = buf; | 1363 | *ret_src_buf = buf; |
1363 | } | 1364 | } |
1364 | 1365 | ||
1365 | return src_page; | 1366 | return src_page; |
1366 | } | 1367 | } |
1367 | 1368 | ||
1368 | static void ocfs2_put_write_source(struct ocfs2_buffered_write_priv *bp, | 1369 | static void ocfs2_put_write_source(struct page *page) |
1369 | struct page *page) | ||
1370 | { | 1370 | { |
1371 | if (page) { | 1371 | if (page) { |
1372 | kunmap(page); | 1372 | kunmap(page); |
@@ -1382,10 +1382,12 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, | |||
1382 | { | 1382 | { |
1383 | int ret = 0; | 1383 | int ret = 0; |
1384 | ssize_t copied, total = 0; | 1384 | ssize_t copied, total = 0; |
1385 | size_t iov_offset = 0; | 1385 | size_t iov_offset = 0, bytes; |
1386 | loff_t pos; | ||
1386 | const struct iovec *cur_iov = iov; | 1387 | const struct iovec *cur_iov = iov; |
1387 | struct ocfs2_buffered_write_priv bp; | 1388 | struct page *user_page, *page; |
1388 | struct page *page; | 1389 | char *buf, *dst; |
1390 | void *fsdata; | ||
1389 | 1391 | ||
1390 | /* | 1392 | /* |
1391 | * handle partial DIO write. Adjust cur_iov if needed. | 1393 | * handle partial DIO write. Adjust cur_iov if needed. |
@@ -1393,21 +1395,38 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, | |||
1393 | ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written); | 1395 | ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written); |
1394 | 1396 | ||
1395 | do { | 1397 | do { |
1396 | bp.b_cur_off = iov_offset; | 1398 | pos = *ppos; |
1397 | bp.b_cur_iov = cur_iov; | ||
1398 | 1399 | ||
1399 | page = ocfs2_get_write_source(&bp, cur_iov, iov_offset); | 1400 | user_page = ocfs2_get_write_source(&buf, cur_iov, iov_offset); |
1400 | if (IS_ERR(page)) { | 1401 | if (IS_ERR(user_page)) { |
1401 | ret = PTR_ERR(page); | 1402 | ret = PTR_ERR(user_page); |
1402 | goto out; | 1403 | goto out; |
1403 | } | 1404 | } |
1404 | 1405 | ||
1405 | copied = ocfs2_buffered_write_cluster(file, *ppos, count, | 1406 | /* Stay within our page boundaries */ |
1406 | ocfs2_map_and_write_user_data, | 1407 | bytes = min((PAGE_CACHE_SIZE - ((unsigned long)pos & ~PAGE_CACHE_MASK)), |
1407 | &bp); | 1408 | (PAGE_CACHE_SIZE - ((unsigned long)buf & ~PAGE_CACHE_MASK))); |
1409 | /* Stay within the vector boundary */ | ||
1410 | bytes = min_t(size_t, bytes, cur_iov->iov_len - iov_offset); | ||
1411 | /* Stay within count */ | ||
1412 | bytes = min(bytes, count); | ||
1413 | |||
1414 | page = NULL; | ||
1415 | ret = ocfs2_write_begin(file, file->f_mapping, pos, bytes, 0, | ||
1416 | &page, &fsdata); | ||
1417 | if (ret) { | ||
1418 | mlog_errno(ret); | ||
1419 | goto out; | ||
1420 | } | ||
1408 | 1421 | ||
1409 | ocfs2_put_write_source(&bp, page); | 1422 | dst = kmap_atomic(page, KM_USER0); |
1423 | memcpy(dst + (pos & (PAGE_CACHE_SIZE - 1)), buf, bytes); | ||
1424 | kunmap_atomic(dst, KM_USER0); | ||
1425 | flush_dcache_page(page); | ||
1426 | ocfs2_put_write_source(user_page); | ||
1410 | 1427 | ||
1428 | copied = ocfs2_write_end(file, file->f_mapping, pos, bytes, | ||
1429 | bytes, page, fsdata); | ||
1411 | if (copied < 0) { | 1430 | if (copied < 0) { |
1412 | mlog_errno(copied); | 1431 | mlog_errno(copied); |
1413 | ret = copied; | 1432 | ret = copied; |
@@ -1415,7 +1434,7 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, | |||
1415 | } | 1434 | } |
1416 | 1435 | ||
1417 | total += copied; | 1436 | total += copied; |
1418 | *ppos = *ppos + copied; | 1437 | *ppos = pos + copied; |
1419 | count -= copied; | 1438 | count -= copied; |
1420 | 1439 | ||
1421 | ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied); | 1440 | ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied); |
@@ -1585,52 +1604,46 @@ static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe, | |||
1585 | struct pipe_buffer *buf, | 1604 | struct pipe_buffer *buf, |
1586 | struct splice_desc *sd) | 1605 | struct splice_desc *sd) |
1587 | { | 1606 | { |
1588 | int ret, count, total = 0; | 1607 | int ret, count; |
1589 | ssize_t copied = 0; | 1608 | ssize_t copied = 0; |
1590 | struct ocfs2_splice_write_priv sp; | 1609 | struct file *file = sd->u.file; |
1610 | unsigned int offset; | ||
1611 | struct page *page = NULL; | ||
1612 | void *fsdata; | ||
1613 | char *src, *dst; | ||
1591 | 1614 | ||
1592 | ret = buf->ops->confirm(pipe, buf); | 1615 | ret = buf->ops->confirm(pipe, buf); |
1593 | if (ret) | 1616 | if (ret) |
1594 | goto out; | 1617 | goto out; |
1595 | 1618 | ||
1596 | sp.s_sd = sd; | 1619 | offset = sd->pos & ~PAGE_CACHE_MASK; |
1597 | sp.s_buf = buf; | ||
1598 | sp.s_pipe = pipe; | ||
1599 | sp.s_offset = sd->pos & ~PAGE_CACHE_MASK; | ||
1600 | sp.s_buf_offset = buf->offset; | ||
1601 | |||
1602 | count = sd->len; | 1620 | count = sd->len; |
1603 | if (count + sp.s_offset > PAGE_CACHE_SIZE) | 1621 | if (count + offset > PAGE_CACHE_SIZE) |
1604 | count = PAGE_CACHE_SIZE - sp.s_offset; | 1622 | count = PAGE_CACHE_SIZE - offset; |
1605 | 1623 | ||
1606 | do { | 1624 | ret = ocfs2_write_begin(file, file->f_mapping, sd->pos, count, 0, |
1607 | /* | 1625 | &page, &fsdata); |
1608 | * splice wants us to copy up to one page at a | 1626 | if (ret) { |
1609 | * time. For pagesize > cluster size, this means we | 1627 | mlog_errno(ret); |
1610 | * might enter ocfs2_buffered_write_cluster() more | 1628 | goto out; |
1611 | * than once, so keep track of our progress here. | 1629 | } |
1612 | */ | ||
1613 | copied = ocfs2_buffered_write_cluster(sd->u.file, | ||
1614 | (loff_t)sd->pos + total, | ||
1615 | count, | ||
1616 | ocfs2_map_and_write_splice_data, | ||
1617 | &sp); | ||
1618 | if (copied < 0) { | ||
1619 | mlog_errno(copied); | ||
1620 | ret = copied; | ||
1621 | goto out; | ||
1622 | } | ||
1623 | 1630 | ||
1624 | count -= copied; | 1631 | src = buf->ops->map(pipe, buf, 1); |
1625 | sp.s_offset += copied; | 1632 | dst = kmap_atomic(page, KM_USER1); |
1626 | sp.s_buf_offset += copied; | 1633 | memcpy(dst + offset, src + buf->offset, count); |
1627 | total += copied; | 1634 | kunmap_atomic(page, KM_USER1); |
1628 | } while (count); | 1635 | buf->ops->unmap(pipe, buf, src); |
1629 | 1636 | ||
1630 | ret = 0; | 1637 | copied = ocfs2_write_end(file, file->f_mapping, sd->pos, count, count, |
1638 | page, fsdata); | ||
1639 | if (copied < 0) { | ||
1640 | mlog_errno(copied); | ||
1641 | ret = copied; | ||
1642 | goto out; | ||
1643 | } | ||
1631 | out: | 1644 | out: |
1632 | 1645 | ||
1633 | return total ? total : ret; | 1646 | return copied ? copied : ret; |
1634 | } | 1647 | } |
1635 | 1648 | ||
1636 | static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe, | 1649 | static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe, |