diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 112 | ||||
-rw-r--r-- | fs/cifs/inode.c | 56 |
3 files changed, 50 insertions, 119 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index fb3e76043c50..d301149b1bb0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -54,6 +54,7 @@ extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | |||
54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
55 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
56 | extern int is_size_safe_to_change(struct cifsInodeInfo *); | 56 | extern int is_size_safe_to_change(struct cifsInodeInfo *); |
57 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | ||
57 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 58 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
58 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 59 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); |
59 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 60 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
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 | { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ca3af4eafcb2..49efdefcff7c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -995,7 +995,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
995 | filemap_fdatawait(direntry->d_inode->i_mapping); | 995 | filemap_fdatawait(direntry->d_inode->i_mapping); |
996 | 996 | ||
997 | if (attrs->ia_valid & ATTR_SIZE) { | 997 | if (attrs->ia_valid & ATTR_SIZE) { |
998 | read_lock(&GlobalSMBSeslock); | ||
999 | /* To avoid spurious oplock breaks from server, in the case of | 998 | /* To avoid spurious oplock breaks from server, in the case of |
1000 | inodes that we already have open, avoid doing path based | 999 | inodes that we already have open, avoid doing path based |
1001 | setting of file size if we can do it by handle. | 1000 | setting of file size if we can do it by handle. |
@@ -1003,49 +1002,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1003 | when the local oplock break takes longer to flush | 1002 | when the local oplock break takes longer to flush |
1004 | writebehind data than the SMB timeout for the SetPathInfo | 1003 | writebehind data than the SMB timeout for the SetPathInfo |
1005 | request would allow */ | 1004 | request would allow */ |
1006 | list_for_each(tmp, &cifsInode->openFileList) { | 1005 | open_file = find_writable_file(cifsInode); |
1007 | open_file = list_entry(tmp, struct cifsFileInfo, | 1006 | if (open_file) { |
1008 | flist); | 1007 | __u16 nfid = open_file->netfid; |
1009 | /* We check if file is open for writing first */ | 1008 | __u32 npid = open_file->pid; |
1010 | if ((open_file->pfile) && | 1009 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, |
1011 | ((open_file->pfile->f_flags & O_RDWR) || | 1010 | nfid, npid, FALSE); |
1012 | (open_file->pfile->f_flags & O_WRONLY))) { | 1011 | cFYI(1,("SetFSize for attrs rc = %d", rc)); |
1013 | if (open_file->invalidHandle == FALSE) { | 1012 | if(rc == -EINVAL) { |
1014 | /* we found a valid, writeable network | 1013 | int bytes_written; |
1015 | file handle to use to try to set the | 1014 | rc = CIFSSMBWrite(xid, pTcon, |
1016 | file size */ | 1015 | nfid, 0, attrs->ia_size, |
1017 | __u16 nfid = open_file->netfid; | 1016 | &bytes_written, NULL, NULL, |
1018 | __u32 npid = open_file->pid; | 1017 | 1 /* 45 seconds */); |
1019 | read_unlock(&GlobalSMBSeslock); | 1018 | cFYI(1,("Wrt seteof rc %d", rc)); |
1020 | found = TRUE; | ||
1021 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
1022 | attrs->ia_size, nfid, npid, | ||
1023 | FALSE); | ||
1024 | cFYI(1, ("SetFileSize by handle " | ||
1025 | "(setattrs) rc = %d", rc)); | ||
1026 | /* Do not need reopen and retry on | ||
1027 | EAGAIN since we will retry by | ||
1028 | pathname below */ | ||
1029 | |||
1030 | /* now that we found one valid file | ||
1031 | handle no sense continuing to loop | ||
1032 | trying others, so break here */ | ||
1033 | if(rc == -EINVAL) { | ||
1034 | int bytes_written; | ||
1035 | rc = CIFSSMBWrite(xid, pTcon, | ||
1036 | nfid, 0, | ||
1037 | attrs->ia_size, | ||
1038 | &bytes_written, NULL, | ||
1039 | NULL, 1 /* 45 sec */); | ||
1040 | cFYI(1,("wrt seteof rc %d",rc)); | ||
1041 | } | ||
1042 | break; | ||
1043 | } | ||
1044 | } | 1019 | } |
1045 | } | 1020 | } |
1046 | if (found == FALSE) | ||
1047 | read_unlock(&GlobalSMBSeslock); | ||
1048 | |||
1049 | if (rc != 0) { | 1021 | if (rc != 0) { |
1050 | /* Set file size by pathname rather than by handle | 1022 | /* Set file size by pathname rather than by handle |
1051 | either because no valid, writeable file handle for | 1023 | either because no valid, writeable file handle for |