aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastryyy@gmail.com>2010-12-14 03:50:41 -0500
committerSteve French <sfrench@us.ibm.com>2011-01-20 16:42:29 -0500
commita70307eeeb25b89f6b2baf3cf3f0cef83c96ba12 (patch)
treef96abbc5d22884fd4c15fdc834c769b7fcf790c4 /fs
parent7a6a19b17ab9103ec708c18befd28f2a3908d4c1 (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')
-rw-r--r--fs/cifs/cifsfs.c4
-rw-r--r--fs/cifs/cifsfs.h4
-rw-r--r--fs/cifs/file.c116
3 files changed, 84 insertions, 40 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e24d966fb214..a8323f1dc1c4 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -736,7 +736,7 @@ const struct file_operations cifs_file_ops = {
736const struct file_operations cifs_file_strict_ops = { 736const struct file_operations cifs_file_strict_ops = {
737 .read = do_sync_read, 737 .read = do_sync_read,
738 .write = do_sync_write, 738 .write = do_sync_write,
739 .aio_read = generic_file_aio_read, 739 .aio_read = cifs_strict_readv,
740 .aio_write = cifs_file_aio_write, 740 .aio_write = cifs_file_aio_write,
741 .open = cifs_open, 741 .open = cifs_open,
742 .release = cifs_close, 742 .release = cifs_close,
@@ -792,7 +792,7 @@ const struct file_operations cifs_file_nobrl_ops = {
792const struct file_operations cifs_file_strict_nobrl_ops = { 792const struct file_operations cifs_file_strict_nobrl_ops = {
793 .read = do_sync_read, 793 .read = do_sync_read,
794 .write = do_sync_write, 794 .write = do_sync_write,
795 .aio_read = generic_file_aio_read, 795 .aio_read = cifs_strict_readv,
796 .aio_write = cifs_file_aio_write, 796 .aio_write = cifs_file_aio_write,
797 .open = cifs_open, 797 .open = cifs_open,
798 .release = cifs_close, 798 .release = cifs_close,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 710072e36912..f23206d46531 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -81,7 +81,9 @@ extern int cifs_open(struct inode *inode, struct file *file);
81extern int cifs_close(struct inode *inode, struct file *file); 81extern int cifs_close(struct inode *inode, struct file *file);
82extern int cifs_closedir(struct inode *inode, struct file *file); 82extern int cifs_closedir(struct inode *inode, struct file *file);
83extern ssize_t cifs_user_read(struct file *file, char __user *read_data, 83extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
84 size_t read_size, loff_t *poffset); 84 size_t read_size, loff_t *poffset);
85extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
86 unsigned long nr_segs, loff_t pos);
85extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, 87extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
86 size_t write_size, loff_t *poffset); 88 size_t write_size, loff_t *poffset);
87extern int cifs_lock(struct file *, int, struct file_lock *); 89extern int cifs_lock(struct file *, int, struct file_lock *);
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
1622ssize_t cifs_user_read(struct file *file, char __user *read_data, 1622static ssize_t
1623 size_t read_size, loff_t *poffset) 1623cifs_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
1701ssize_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
1711static 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
1723ssize_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
1703static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, 1745static 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;