diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 175 |
1 files changed, 130 insertions, 45 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index bd2a028af833..d7d65a70678e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
287 | struct inode *inode = cifs_file->dentry->d_inode; | 287 | struct inode *inode = cifs_file->dentry->d_inode; |
288 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); | 288 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); |
289 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 289 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
290 | struct cifsLockInfo *li, *tmp; | 291 | struct cifsLockInfo *li, *tmp; |
291 | 292 | ||
292 | spin_lock(&cifs_file_list_lock); | 293 | spin_lock(&cifs_file_list_lock); |
@@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
302 | if (list_empty(&cifsi->openFileList)) { | 303 | if (list_empty(&cifsi->openFileList)) { |
303 | cFYI(1, "closing last open instance for inode %p", | 304 | cFYI(1, "closing last open instance for inode %p", |
304 | cifs_file->dentry->d_inode); | 305 | cifs_file->dentry->d_inode); |
306 | |||
307 | /* in strict cache mode we need invalidate mapping on the last | ||
308 | close because it may cause a error when we open this file | ||
309 | again and get at least level II oplock */ | ||
310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) | ||
311 | CIFS_I(inode)->invalid_mapping = true; | ||
312 | |||
305 | cifs_set_oplock_level(cifsi, 0); | 313 | cifs_set_oplock_level(cifsi, 0); |
306 | } | 314 | } |
307 | spin_unlock(&cifs_file_list_lock); | 315 | spin_unlock(&cifs_file_list_lock); |
@@ -1520,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1520 | return rc; | 1528 | return rc; |
1521 | } | 1529 | } |
1522 | 1530 | ||
1523 | int cifs_fsync(struct file *file, int datasync) | 1531 | int cifs_strict_fsync(struct file *file, int datasync) |
1524 | { | 1532 | { |
1525 | int xid; | 1533 | int xid; |
1526 | int rc = 0; | 1534 | int rc = 0; |
1527 | struct cifsTconInfo *tcon; | 1535 | struct cifsTconInfo *tcon; |
1528 | struct cifsFileInfo *smbfile = file->private_data; | 1536 | struct cifsFileInfo *smbfile = file->private_data; |
1529 | struct inode *inode = file->f_path.dentry->d_inode; | 1537 | struct inode *inode = file->f_path.dentry->d_inode; |
1538 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1530 | 1539 | ||
1531 | xid = GetXid(); | 1540 | xid = GetXid(); |
1532 | 1541 | ||
1533 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | 1542 | cFYI(1, "Sync file - name: %s datasync: 0x%x", |
1534 | file->f_path.dentry->d_name.name, datasync); | 1543 | file->f_path.dentry->d_name.name, datasync); |
1535 | 1544 | ||
1536 | rc = filemap_write_and_wait(inode->i_mapping); | 1545 | if (!CIFS_I(inode)->clientCanCacheRead) |
1537 | if (rc == 0) { | 1546 | cifs_invalidate_mapping(inode); |
1538 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1539 | 1547 | ||
1540 | tcon = tlink_tcon(smbfile->tlink); | 1548 | tcon = tlink_tcon(smbfile->tlink); |
1541 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | 1549 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) |
1542 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | 1550 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); |
1543 | } | 1551 | |
1552 | FreeXid(xid); | ||
1553 | return rc; | ||
1554 | } | ||
1555 | |||
1556 | int cifs_fsync(struct file *file, int datasync) | ||
1557 | { | ||
1558 | int xid; | ||
1559 | int rc = 0; | ||
1560 | struct cifsTconInfo *tcon; | ||
1561 | struct cifsFileInfo *smbfile = file->private_data; | ||
1562 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1563 | |||
1564 | xid = GetXid(); | ||
1565 | |||
1566 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | ||
1567 | file->f_path.dentry->d_name.name, datasync); | ||
1568 | |||
1569 | tcon = tlink_tcon(smbfile->tlink); | ||
1570 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
1571 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | ||
1544 | 1572 | ||
1545 | FreeXid(xid); | 1573 | FreeXid(xid); |
1546 | return rc; | 1574 | return rc; |
@@ -1591,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
1591 | return rc; | 1619 | return rc; |
1592 | } | 1620 | } |
1593 | 1621 | ||
1594 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | 1622 | static ssize_t |
1595 | 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) | ||
1596 | { | 1625 | { |
1597 | int rc = -EACCES; | 1626 | int rc; |
1598 | unsigned int bytes_read = 0; | 1627 | int xid; |
1599 | unsigned int total_read = 0; | 1628 | unsigned int total_read, bytes_read = 0; |
1600 | unsigned int current_read_size; | 1629 | size_t len, cur_len; |
1630 | int iov_offset = 0; | ||
1601 | struct cifs_sb_info *cifs_sb; | 1631 | struct cifs_sb_info *cifs_sb; |
1602 | struct cifsTconInfo *pTcon; | 1632 | struct cifsTconInfo *pTcon; |
1603 | int xid; | ||
1604 | struct cifsFileInfo *open_file; | 1633 | struct cifsFileInfo *open_file; |
1605 | char *smb_read_data; | ||
1606 | char __user *current_offset; | ||
1607 | 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; | ||
1608 | 1643 | ||
1609 | xid = GetXid(); | 1644 | xid = GetXid(); |
1610 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1645 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1611 | 1646 | ||
1612 | if (file->private_data == NULL) { | ||
1613 | rc = -EBADF; | ||
1614 | FreeXid(xid); | ||
1615 | return rc; | ||
1616 | } | ||
1617 | open_file = file->private_data; | 1647 | open_file = file->private_data; |
1618 | pTcon = tlink_tcon(open_file->tlink); | 1648 | pTcon = tlink_tcon(open_file->tlink); |
1619 | 1649 | ||
1620 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1650 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1621 | cFYI(1, "attempting read on write only file instance"); | 1651 | cFYI(1, "attempting read on write only file instance"); |
1622 | 1652 | ||
1623 | for (total_read = 0, current_offset = read_data; | 1653 | for (total_read = 0; total_read < len; total_read += bytes_read) { |
1624 | read_size > total_read; | 1654 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
1625 | total_read += bytes_read, current_offset += bytes_read) { | ||
1626 | current_read_size = min_t(const int, read_size - total_read, | ||
1627 | cifs_sb->rsize); | ||
1628 | rc = -EAGAIN; | 1655 | rc = -EAGAIN; |
1629 | smb_read_data = NULL; | 1656 | read_data = NULL; |
1657 | |||
1630 | while (rc == -EAGAIN) { | 1658 | while (rc == -EAGAIN) { |
1631 | int buf_type = CIFS_NO_BUFFER; | 1659 | int buf_type = CIFS_NO_BUFFER; |
1632 | if (open_file->invalidHandle) { | 1660 | if (open_file->invalidHandle) { |
@@ -1634,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1634 | if (rc != 0) | 1662 | if (rc != 0) |
1635 | break; | 1663 | break; |
1636 | } | 1664 | } |
1637 | rc = CIFSSMBRead(xid, pTcon, | 1665 | rc = CIFSSMBRead(xid, pTcon, open_file->netfid, |
1638 | open_file->netfid, | 1666 | cur_len, *poffset, &bytes_read, |
1639 | current_read_size, *poffset, | 1667 | &read_data, &buf_type); |
1640 | &bytes_read, &smb_read_data, | 1668 | pSMBr = (struct smb_com_read_rsp *)read_data; |
1641 | &buf_type); | 1669 | if (read_data) { |
1642 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1670 | char *data_offset = read_data + 4 + |
1643 | if (smb_read_data) { | 1671 | le16_to_cpu(pSMBr->DataOffset); |
1644 | if (copy_to_user(current_offset, | 1672 | if (memcpy_toiovecend(iov, data_offset, |
1645 | smb_read_data + | 1673 | iov_offset, bytes_read)) |
1646 | 4 /* RFC1001 length field */ + | ||
1647 | le16_to_cpu(pSMBr->DataOffset), | ||
1648 | bytes_read)) | ||
1649 | rc = -EFAULT; | 1674 | rc = -EFAULT; |
1650 | |||
1651 | if (buf_type == CIFS_SMALL_BUFFER) | 1675 | if (buf_type == CIFS_SMALL_BUFFER) |
1652 | cifs_small_buf_release(smb_read_data); | 1676 | cifs_small_buf_release(read_data); |
1653 | else if (buf_type == CIFS_LARGE_BUFFER) | 1677 | else if (buf_type == CIFS_LARGE_BUFFER) |
1654 | cifs_buf_release(smb_read_data); | 1678 | cifs_buf_release(read_data); |
1655 | smb_read_data = NULL; | 1679 | read_data = NULL; |
1680 | iov_offset += bytes_read; | ||
1656 | } | 1681 | } |
1657 | } | 1682 | } |
1683 | |||
1658 | if (rc || (bytes_read == 0)) { | 1684 | if (rc || (bytes_read == 0)) { |
1659 | if (total_read) { | 1685 | if (total_read) { |
1660 | break; | 1686 | break; |
@@ -1667,13 +1693,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1667 | *poffset += bytes_read; | 1693 | *poffset += bytes_read; |
1668 | } | 1694 | } |
1669 | } | 1695 | } |
1696 | |||
1670 | FreeXid(xid); | 1697 | FreeXid(xid); |
1671 | return total_read; | 1698 | return total_read; |
1672 | } | 1699 | } |
1673 | 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 | } | ||
1674 | 1744 | ||
1675 | 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, |
1676 | loff_t *poffset) | 1746 | loff_t *poffset) |
1677 | { | 1747 | { |
1678 | int rc = -EACCES; | 1748 | int rc = -EACCES; |
1679 | unsigned int bytes_read = 0; | 1749 | unsigned int bytes_read = 0; |
@@ -1741,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1741 | return total_read; | 1811 | return total_read; |
1742 | } | 1812 | } |
1743 | 1813 | ||
1814 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) | ||
1815 | { | ||
1816 | int rc, xid; | ||
1817 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1818 | |||
1819 | xid = GetXid(); | ||
1820 | |||
1821 | if (!CIFS_I(inode)->clientCanCacheRead) | ||
1822 | cifs_invalidate_mapping(inode); | ||
1823 | |||
1824 | rc = generic_file_mmap(file, vma); | ||
1825 | FreeXid(xid); | ||
1826 | return rc; | ||
1827 | } | ||
1828 | |||
1744 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | 1829 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) |
1745 | { | 1830 | { |
1746 | int rc, xid; | 1831 | int rc, xid; |