diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 112 |
1 files changed, 35 insertions, 77 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 941108352547..94875455d7fa 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -904,6 +904,25 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
904 | return total_written; | 904 | return total_written; |
905 | } | 905 | } |
906 | 906 | ||
907 | static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | ||
908 | { | ||
909 | struct cifsFileInfo *open_file; | ||
910 | |||
911 | read_lock(&GlobalSMBSeslock); | ||
912 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | ||
913 | if (open_file->closePend) | ||
914 | continue; | ||
915 | if (open_file->pfile && | ||
916 | ((open_file->pfile->f_flags & O_RDWR) || | ||
917 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
918 | read_unlock(&GlobalSMBSeslock); | ||
919 | return open_file; | ||
920 | } | ||
921 | } | ||
922 | read_unlock(&GlobalSMBSeslock); | ||
923 | return NULL; | ||
924 | } | ||
925 | |||
907 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 926 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
908 | { | 927 | { |
909 | struct address_space *mapping = page->mapping; | 928 | struct address_space *mapping = page->mapping; |
@@ -914,10 +933,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
914 | struct cifs_sb_info *cifs_sb; | 933 | struct cifs_sb_info *cifs_sb; |
915 | struct cifsTconInfo *pTcon; | 934 | struct cifsTconInfo *pTcon; |
916 | struct inode *inode; | 935 | struct inode *inode; |
917 | struct cifsInodeInfo *cifsInode; | 936 | struct cifsFileInfo *open_file; |
918 | struct cifsFileInfo *open_file = NULL; | ||
919 | struct list_head *tmp; | ||
920 | struct list_head *tmp1; | ||
921 | 937 | ||
922 | if (!mapping || !mapping->host) | 938 | if (!mapping || !mapping->host) |
923 | return -EFAULT; | 939 | return -EFAULT; |
@@ -945,49 +961,19 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
945 | if (mapping->host->i_size - offset < (loff_t)to) | 961 | if (mapping->host->i_size - offset < (loff_t)to) |
946 | to = (unsigned)(mapping->host->i_size - offset); | 962 | to = (unsigned)(mapping->host->i_size - offset); |
947 | 963 | ||
948 | cifsInode = CIFS_I(mapping->host); | 964 | open_file = find_writable_file(CIFS_I(mapping->host)); |
949 | read_lock(&GlobalSMBSeslock); | 965 | if (open_file) { |
950 | /* BB we should start at the end */ | 966 | bytes_written = cifs_write(open_file->pfile, write_data, |
951 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 967 | to-from, &offset); |
952 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
953 | if (open_file->closePend) | ||
954 | continue; | ||
955 | /* We check if file is open for writing first */ | ||
956 | if ((open_file->pfile) && | ||
957 | ((open_file->pfile->f_flags & O_RDWR) || | ||
958 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
959 | read_unlock(&GlobalSMBSeslock); | ||
960 | bytes_written = cifs_write(open_file->pfile, | ||
961 | write_data, to-from, | ||
962 | &offset); | ||
963 | read_lock(&GlobalSMBSeslock); | ||
964 | /* Does mm or vfs already set times? */ | 968 | /* Does mm or vfs already set times? */ |
965 | inode->i_atime = | 969 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
966 | inode->i_mtime = current_fs_time(inode->i_sb); | 970 | if ((bytes_written > 0) && (offset)) { |
967 | if ((bytes_written > 0) && (offset)) { | 971 | rc = 0; |
968 | rc = 0; | 972 | } else if (bytes_written < 0) { |
969 | } else if (bytes_written < 0) { | 973 | if (rc != -EBADF) |
970 | if (rc == -EBADF) { | 974 | rc = bytes_written; |
971 | /* have seen a case in which kernel seemed to | ||
972 | have closed/freed a file even with writes | ||
973 | active so we might as well see if there are | ||
974 | other file structs to try for the same | ||
975 | inode before giving up */ | ||
976 | continue; | ||
977 | } else | ||
978 | rc = bytes_written; | ||
979 | } | ||
980 | break; /* now that we found a valid file handle and | ||
981 | tried to write to it we are done, no sense | ||
982 | continuing to loop looking for another */ | ||
983 | } | ||
984 | if (tmp->next == NULL) { | ||
985 | cFYI(1, ("File instance %p removed", tmp)); | ||
986 | break; | ||
987 | } | 975 | } |
988 | } | 976 | } else { |
989 | read_unlock(&GlobalSMBSeslock); | ||
990 | if (open_file == NULL) { | ||
991 | cFYI(1, ("No writeable filehandles for inode")); | 977 | cFYI(1, ("No writeable filehandles for inode")); |
992 | rc = -EIO; | 978 | rc = -EIO; |
993 | } | 979 | } |
@@ -1604,40 +1590,12 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
1604 | page caching in the current Linux kernel design */ | 1590 | page caching in the current Linux kernel design */ |
1605 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | 1591 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) |
1606 | { | 1592 | { |
1607 | struct list_head *tmp; | 1593 | if (cifsInode && find_writable_file(cifsInode)) |
1608 | struct list_head *tmp1; | 1594 | return 0; |
1609 | struct cifsFileInfo *open_file = NULL; | 1595 | else |
1610 | int rc = TRUE; | 1596 | return 1; |
1611 | |||
1612 | if (cifsInode == NULL) | ||
1613 | return rc; | ||
1614 | |||
1615 | read_lock(&GlobalSMBSeslock); | ||
1616 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | ||
1617 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
1618 | if (open_file == NULL) | ||
1619 | break; | ||
1620 | if (open_file->closePend) | ||
1621 | continue; | ||
1622 | /* We check if file is open for writing, | ||
1623 | BB we could supplement this with a check to see if file size | ||
1624 | changes have been flushed to server - ie inode metadata dirty */ | ||
1625 | if ((open_file->pfile) && | ||
1626 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1627 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1628 | rc = FALSE; | ||
1629 | break; | ||
1630 | } | ||
1631 | if (tmp->next == NULL) { | ||
1632 | cFYI(1, ("File instance %p removed", tmp)); | ||
1633 | break; | ||
1634 | } | ||
1635 | } | ||
1636 | read_unlock(&GlobalSMBSeslock); | ||
1637 | return rc; | ||
1638 | } | 1597 | } |
1639 | 1598 | ||
1640 | |||
1641 | static int cifs_prepare_write(struct file *file, struct page *page, | 1599 | static int cifs_prepare_write(struct file *file, struct page *page, |
1642 | unsigned from, unsigned to) | 1600 | unsigned from, unsigned to) |
1643 | { | 1601 | { |