diff options
| -rw-r--r-- | fs/cifs/cifsfs.c | 4 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 4 | ||||
| -rw-r--r-- | fs/cifs/file.c | 116 |
3 files changed, 84 insertions, 40 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e24d966fb21..a8323f1dc1c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -736,7 +736,7 @@ const struct file_operations cifs_file_ops = { | |||
| 736 | const struct file_operations cifs_file_strict_ops = { | 736 | const 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 = { | |||
| 792 | const struct file_operations cifs_file_strict_nobrl_ops = { | 792 | const 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 710072e3691..f23206d4653 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); | |||
| 81 | extern int cifs_close(struct inode *inode, struct file *file); | 81 | extern int cifs_close(struct inode *inode, struct file *file); |
| 82 | extern int cifs_closedir(struct inode *inode, struct file *file); | 82 | extern int cifs_closedir(struct inode *inode, struct file *file); |
| 83 | extern ssize_t cifs_user_read(struct file *file, char __user *read_data, | 83 | extern 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); |
| 85 | extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | ||
| 86 | unsigned long nr_segs, loff_t pos); | ||
| 85 | extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 87 | extern 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); |
| 87 | extern int cifs_lock(struct file *, int, struct file_lock *); | 89 | extern int cifs_lock(struct file *, int, struct file_lock *); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0b32377ef8b..d7d65a70678 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; |
