diff options
author | Pavel Shilovsky <piastryyy@gmail.com> | 2010-12-14 03:50:41 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-01-20 16:42:29 -0500 |
commit | a70307eeeb25b89f6b2baf3cf3f0cef83c96ba12 (patch) | |
tree | f96abbc5d22884fd4c15fdc834c769b7fcf790c4 /fs/cifs/file.c | |
parent | 7a6a19b17ab9103ec708c18befd28f2a3908d4c1 (diff) |
CIFS: Implement cifs_strict_readv (try #4)
Read from the cache if we have at least Level II oplock - otherwise
read from the server. Add cifs_user_readv to let the client read into
iovec buffers.
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 116 |
1 files changed, 79 insertions, 37 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0b32377ef8b7..d7d65a70678e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1619,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
1619 | return rc; | 1619 | return rc; |
1620 | } | 1620 | } |
1621 | 1621 | ||
1622 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | 1622 | static ssize_t |
1623 | size_t read_size, loff_t *poffset) | 1623 | cifs_iovec_read(struct file *file, const struct iovec *iov, |
1624 | unsigned long nr_segs, loff_t *poffset) | ||
1624 | { | 1625 | { |
1625 | int rc = -EACCES; | 1626 | int rc; |
1626 | unsigned int bytes_read = 0; | 1627 | int xid; |
1627 | unsigned int total_read = 0; | 1628 | unsigned int total_read, bytes_read = 0; |
1628 | unsigned int current_read_size; | 1629 | size_t len, cur_len; |
1630 | int iov_offset = 0; | ||
1629 | struct cifs_sb_info *cifs_sb; | 1631 | struct cifs_sb_info *cifs_sb; |
1630 | struct cifsTconInfo *pTcon; | 1632 | struct cifsTconInfo *pTcon; |
1631 | int xid; | ||
1632 | struct cifsFileInfo *open_file; | 1633 | struct cifsFileInfo *open_file; |
1633 | char *smb_read_data; | ||
1634 | char __user *current_offset; | ||
1635 | struct smb_com_read_rsp *pSMBr; | 1634 | struct smb_com_read_rsp *pSMBr; |
1635 | char *read_data; | ||
1636 | |||
1637 | if (!nr_segs) | ||
1638 | return 0; | ||
1639 | |||
1640 | len = iov_length(iov, nr_segs); | ||
1641 | if (!len) | ||
1642 | return 0; | ||
1636 | 1643 | ||
1637 | xid = GetXid(); | 1644 | xid = GetXid(); |
1638 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1645 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1639 | 1646 | ||
1640 | if (file->private_data == NULL) { | ||
1641 | rc = -EBADF; | ||
1642 | FreeXid(xid); | ||
1643 | return rc; | ||
1644 | } | ||
1645 | open_file = file->private_data; | 1647 | open_file = file->private_data; |
1646 | pTcon = tlink_tcon(open_file->tlink); | 1648 | pTcon = tlink_tcon(open_file->tlink); |
1647 | 1649 | ||
1648 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1650 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1649 | cFYI(1, "attempting read on write only file instance"); | 1651 | cFYI(1, "attempting read on write only file instance"); |
1650 | 1652 | ||
1651 | for (total_read = 0, current_offset = read_data; | 1653 | for (total_read = 0; total_read < len; total_read += bytes_read) { |
1652 | read_size > total_read; | 1654 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
1653 | total_read += bytes_read, current_offset += bytes_read) { | ||
1654 | current_read_size = min_t(const int, read_size - total_read, | ||
1655 | cifs_sb->rsize); | ||
1656 | rc = -EAGAIN; | 1655 | rc = -EAGAIN; |
1657 | smb_read_data = NULL; | 1656 | read_data = NULL; |
1657 | |||
1658 | while (rc == -EAGAIN) { | 1658 | while (rc == -EAGAIN) { |
1659 | int buf_type = CIFS_NO_BUFFER; | 1659 | int buf_type = CIFS_NO_BUFFER; |
1660 | if (open_file->invalidHandle) { | 1660 | if (open_file->invalidHandle) { |
@@ -1662,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1662 | if (rc != 0) | 1662 | if (rc != 0) |
1663 | break; | 1663 | break; |
1664 | } | 1664 | } |
1665 | rc = CIFSSMBRead(xid, pTcon, | 1665 | rc = CIFSSMBRead(xid, pTcon, open_file->netfid, |
1666 | open_file->netfid, | 1666 | cur_len, *poffset, &bytes_read, |
1667 | current_read_size, *poffset, | 1667 | &read_data, &buf_type); |
1668 | &bytes_read, &smb_read_data, | 1668 | pSMBr = (struct smb_com_read_rsp *)read_data; |
1669 | &buf_type); | 1669 | if (read_data) { |
1670 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1670 | char *data_offset = read_data + 4 + |
1671 | if (smb_read_data) { | 1671 | le16_to_cpu(pSMBr->DataOffset); |
1672 | if (copy_to_user(current_offset, | 1672 | if (memcpy_toiovecend(iov, data_offset, |
1673 | smb_read_data + | 1673 | iov_offset, bytes_read)) |
1674 | 4 /* RFC1001 length field */ + | ||
1675 | le16_to_cpu(pSMBr->DataOffset), | ||
1676 | bytes_read)) | ||
1677 | rc = -EFAULT; | 1674 | rc = -EFAULT; |
1678 | |||
1679 | if (buf_type == CIFS_SMALL_BUFFER) | 1675 | if (buf_type == CIFS_SMALL_BUFFER) |
1680 | cifs_small_buf_release(smb_read_data); | 1676 | cifs_small_buf_release(read_data); |
1681 | else if (buf_type == CIFS_LARGE_BUFFER) | 1677 | else if (buf_type == CIFS_LARGE_BUFFER) |
1682 | cifs_buf_release(smb_read_data); | 1678 | cifs_buf_release(read_data); |
1683 | smb_read_data = NULL; | 1679 | read_data = NULL; |
1680 | iov_offset += bytes_read; | ||
1684 | } | 1681 | } |
1685 | } | 1682 | } |
1683 | |||
1686 | if (rc || (bytes_read == 0)) { | 1684 | if (rc || (bytes_read == 0)) { |
1687 | if (total_read) { | 1685 | if (total_read) { |
1688 | break; | 1686 | break; |
@@ -1695,13 +1693,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1695 | *poffset += bytes_read; | 1693 | *poffset += bytes_read; |
1696 | } | 1694 | } |
1697 | } | 1695 | } |
1696 | |||
1698 | FreeXid(xid); | 1697 | FreeXid(xid); |
1699 | return total_read; | 1698 | return total_read; |
1700 | } | 1699 | } |
1701 | 1700 | ||
1701 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | ||
1702 | size_t read_size, loff_t *poffset) | ||
1703 | { | ||
1704 | struct iovec iov; | ||
1705 | iov.iov_base = read_data; | ||
1706 | iov.iov_len = read_size; | ||
1707 | |||
1708 | return cifs_iovec_read(file, &iov, 1, poffset); | ||
1709 | } | ||
1710 | |||
1711 | static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | ||
1712 | unsigned long nr_segs, loff_t pos) | ||
1713 | { | ||
1714 | ssize_t read; | ||
1715 | |||
1716 | read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos); | ||
1717 | if (read > 0) | ||
1718 | iocb->ki_pos = pos; | ||
1719 | |||
1720 | return read; | ||
1721 | } | ||
1722 | |||
1723 | ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | ||
1724 | unsigned long nr_segs, loff_t pos) | ||
1725 | { | ||
1726 | struct inode *inode; | ||
1727 | |||
1728 | inode = iocb->ki_filp->f_path.dentry->d_inode; | ||
1729 | |||
1730 | if (CIFS_I(inode)->clientCanCacheRead) | ||
1731 | return generic_file_aio_read(iocb, iov, nr_segs, pos); | ||
1732 | |||
1733 | /* | ||
1734 | * In strict cache mode we need to read from the server all the time | ||
1735 | * if we don't have level II oplock because the server can delay mtime | ||
1736 | * change - so we can't make a decision about inode invalidating. | ||
1737 | * And we can also fail with pagereading if there are mandatory locks | ||
1738 | * on pages affected by this read but not on the region from pos to | ||
1739 | * pos+len-1. | ||
1740 | */ | ||
1741 | |||
1742 | return cifs_user_readv(iocb, iov, nr_segs, pos); | ||
1743 | } | ||
1702 | 1744 | ||
1703 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | 1745 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, |
1704 | loff_t *poffset) | 1746 | loff_t *poffset) |
1705 | { | 1747 | { |
1706 | int rc = -EACCES; | 1748 | int rc = -EACCES; |
1707 | unsigned int bytes_read = 0; | 1749 | unsigned int bytes_read = 0; |