aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/file.c112
-rw-r--r--fs/cifs/inode.c56
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);
54extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); 54extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
55extern int is_valid_oplock_break(struct smb_hdr *smb); 55extern int is_valid_oplock_break(struct smb_hdr *smb);
56extern int is_size_safe_to_change(struct cifsInodeInfo *); 56extern int is_size_safe_to_change(struct cifsInodeInfo *);
57extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
57extern unsigned int smbCalcSize(struct smb_hdr *ptr); 58extern unsigned int smbCalcSize(struct smb_hdr *ptr);
58extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); 59extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
59extern int decode_negTokenInit(unsigned char *security_blob, int length, 60extern 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
907static 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
907static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) 926static 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 */
1605int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) 1591int 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
1641static int cifs_prepare_write(struct file *file, struct page *page, 1599static 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