diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 466 |
1 files changed, 333 insertions, 133 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3497125189df..da4f5e10b3cc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -21,11 +21,15 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/backing-dev.h> | ||
24 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
25 | #include <linux/fcntl.h> | 26 | #include <linux/fcntl.h> |
27 | #include <linux/mpage.h> | ||
26 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
27 | #include <linux/pagevec.h> | 29 | #include <linux/pagevec.h> |
28 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/writeback.h> | ||
32 | #include <linux/delay.h> | ||
29 | #include <asm/div64.h> | 33 | #include <asm/div64.h> |
30 | #include "cifsfs.h" | 34 | #include "cifsfs.h" |
31 | #include "cifspdu.h" | 35 | #include "cifspdu.h" |
@@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
47 | private_data->pInode = inode; | 51 | private_data->pInode = inode; |
48 | private_data->invalidHandle = FALSE; | 52 | private_data->invalidHandle = FALSE; |
49 | private_data->closePend = FALSE; | 53 | private_data->closePend = FALSE; |
54 | /* we have to track num writers to the inode, since writepages | ||
55 | does not tell us which handle the write is for so there can | ||
56 | be a close (overlapping with write) of the filehandle that | ||
57 | cifs_writepages chose to use */ | ||
58 | atomic_set(&private_data->wrtPending,0); | ||
50 | 59 | ||
51 | return private_data; | 60 | return private_data; |
52 | } | 61 | } |
@@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file) | |||
256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | 265 | CREATE_NOT_DIR, &netfid, &oplock, buf, |
257 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 266 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
258 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 267 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
268 | if (rc == -EIO) { | ||
269 | /* Old server, try legacy style OpenX */ | ||
270 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
271 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
272 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
273 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
274 | } | ||
259 | if (rc) { | 275 | if (rc) { |
260 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 276 | cFYI(1, ("cifs_open returned 0x%x ", rc)); |
261 | goto out; | 277 | goto out; |
@@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file) | |||
463 | /* no sense reconnecting to close a file that is | 479 | /* no sense reconnecting to close a file that is |
464 | already closed */ | 480 | already closed */ |
465 | if (pTcon->tidStatus != CifsNeedReconnect) { | 481 | if (pTcon->tidStatus != CifsNeedReconnect) { |
482 | int timeout = 2; | ||
483 | while((atomic_read(&pSMBFile->wrtPending) != 0) | ||
484 | && (timeout < 1000) ) { | ||
485 | /* Give write a better chance to get to | ||
486 | server ahead of the close. We do not | ||
487 | want to add a wait_q here as it would | ||
488 | increase the memory utilization as | ||
489 | the struct would be in each open file, | ||
490 | but this should give enough time to | ||
491 | clear the socket */ | ||
492 | cERROR(1,("close with pending writes")); | ||
493 | msleep(timeout); | ||
494 | timeout *= 4; | ||
495 | } | ||
466 | write_unlock(&file->f_owner.lock); | 496 | write_unlock(&file->f_owner.lock); |
467 | rc = CIFSSMBClose(xid, pTcon, | 497 | rc = CIFSSMBClose(xid, pTcon, |
468 | pSMBFile->netfid); | 498 | pSMBFile->netfid); |
@@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
744 | 15 seconds is plenty */ | 774 | 15 seconds is plenty */ |
745 | } | 775 | } |
746 | 776 | ||
747 | #ifdef CONFIG_CIFS_STATS | 777 | cifs_stats_bytes_written(pTcon, total_written); |
748 | if (total_written > 0) { | ||
749 | atomic_inc(&pTcon->num_writes); | ||
750 | spin_lock(&pTcon->stat_lock); | ||
751 | pTcon->bytes_written += total_written; | ||
752 | spin_unlock(&pTcon->stat_lock); | ||
753 | } | ||
754 | #endif | ||
755 | 778 | ||
756 | /* since the write may have blocked check these pointers again */ | 779 | /* since the write may have blocked check these pointers again */ |
757 | if (file->f_dentry) { | 780 | if (file->f_dentry) { |
@@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
791 | 814 | ||
792 | pTcon = cifs_sb->tcon; | 815 | pTcon = cifs_sb->tcon; |
793 | 816 | ||
794 | /* cFYI(1, | 817 | cFYI(1,("write %zd bytes to offset %lld of %s", write_size, |
795 | (" write %d bytes to offset %lld of %s", write_size, | 818 | *poffset, file->f_dentry->d_name.name)); |
796 | *poffset, file->f_dentry->d_name.name)); */ | ||
797 | 819 | ||
798 | if (file->private_data == NULL) | 820 | if (file->private_data == NULL) |
799 | return -EBADF; | 821 | return -EBADF; |
@@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
846 | if (rc != 0) | 868 | if (rc != 0) |
847 | break; | 869 | break; |
848 | } | 870 | } |
849 | 871 | #ifdef CONFIG_CIFS_EXPERIMENTAL | |
872 | /* BB FIXME We can not sign across two buffers yet */ | ||
873 | if((experimEnabled) && ((pTcon->ses->server->secMode & | ||
874 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | ||
875 | struct kvec iov[2]; | ||
876 | unsigned int len; | ||
877 | |||
878 | len = min((size_t)cifs_sb->wsize, | ||
879 | write_size - total_written); | ||
880 | /* iov[0] is reserved for smb header */ | ||
881 | iov[1].iov_base = (char *)write_data + | ||
882 | total_written; | ||
883 | iov[1].iov_len = len; | ||
884 | rc = CIFSSMBWrite2(xid, pTcon, | ||
885 | open_file->netfid, len, | ||
886 | *poffset, &bytes_written, | ||
887 | iov, 1, long_op); | ||
888 | } else | ||
889 | /* BB FIXME fixup indentation of line below */ | ||
890 | #endif | ||
850 | rc = CIFSSMBWrite(xid, pTcon, | 891 | rc = CIFSSMBWrite(xid, pTcon, |
851 | open_file->netfid, | 892 | open_file->netfid, |
852 | min_t(const int, cifs_sb->wsize, | 893 | min_t(const int, cifs_sb->wsize, |
@@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
867 | 15 seconds is plenty */ | 908 | 15 seconds is plenty */ |
868 | } | 909 | } |
869 | 910 | ||
870 | #ifdef CONFIG_CIFS_STATS | 911 | cifs_stats_bytes_written(pTcon, total_written); |
871 | if (total_written > 0) { | ||
872 | atomic_inc(&pTcon->num_writes); | ||
873 | spin_lock(&pTcon->stat_lock); | ||
874 | pTcon->bytes_written += total_written; | ||
875 | spin_unlock(&pTcon->stat_lock); | ||
876 | } | ||
877 | #endif | ||
878 | 912 | ||
879 | /* since the write may have blocked check these pointers again */ | 913 | /* since the write may have blocked check these pointers again */ |
880 | if (file->f_dentry) { | 914 | if (file->f_dentry) { |
@@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
893 | return total_written; | 927 | return total_written; |
894 | } | 928 | } |
895 | 929 | ||
930 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | ||
931 | { | ||
932 | struct cifsFileInfo *open_file; | ||
933 | int rc; | ||
934 | |||
935 | read_lock(&GlobalSMBSeslock); | ||
936 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | ||
937 | if (open_file->closePend) | ||
938 | continue; | ||
939 | if (open_file->pfile && | ||
940 | ((open_file->pfile->f_flags & O_RDWR) || | ||
941 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
942 | atomic_inc(&open_file->wrtPending); | ||
943 | read_unlock(&GlobalSMBSeslock); | ||
944 | if((open_file->invalidHandle) && | ||
945 | (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { | ||
946 | rc = cifs_reopen_file(&cifs_inode->vfs_inode, | ||
947 | open_file->pfile, FALSE); | ||
948 | /* if it fails, try another handle - might be */ | ||
949 | /* dangerous to hold up writepages with retry */ | ||
950 | if(rc) { | ||
951 | cFYI(1,("failed on reopen file in wp")); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* can not use this handle, no write | ||
954 | pending on this one after all */ | ||
955 | atomic_dec | ||
956 | (&open_file->wrtPending); | ||
957 | continue; | ||
958 | } | ||
959 | } | ||
960 | return open_file; | ||
961 | } | ||
962 | } | ||
963 | read_unlock(&GlobalSMBSeslock); | ||
964 | return NULL; | ||
965 | } | ||
966 | |||
896 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 967 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
897 | { | 968 | { |
898 | struct address_space *mapping = page->mapping; | 969 | struct address_space *mapping = page->mapping; |
@@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
903 | struct cifs_sb_info *cifs_sb; | 974 | struct cifs_sb_info *cifs_sb; |
904 | struct cifsTconInfo *pTcon; | 975 | struct cifsTconInfo *pTcon; |
905 | struct inode *inode; | 976 | struct inode *inode; |
906 | struct cifsInodeInfo *cifsInode; | 977 | struct cifsFileInfo *open_file; |
907 | struct cifsFileInfo *open_file = NULL; | ||
908 | struct list_head *tmp; | ||
909 | struct list_head *tmp1; | ||
910 | 978 | ||
911 | if (!mapping || !mapping->host) | 979 | if (!mapping || !mapping->host) |
912 | return -EFAULT; | 980 | return -EFAULT; |
@@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
934 | if (mapping->host->i_size - offset < (loff_t)to) | 1002 | if (mapping->host->i_size - offset < (loff_t)to) |
935 | to = (unsigned)(mapping->host->i_size - offset); | 1003 | to = (unsigned)(mapping->host->i_size - offset); |
936 | 1004 | ||
937 | cifsInode = CIFS_I(mapping->host); | 1005 | open_file = find_writable_file(CIFS_I(mapping->host)); |
938 | read_lock(&GlobalSMBSeslock); | 1006 | if (open_file) { |
939 | /* BB we should start at the end */ | 1007 | bytes_written = cifs_write(open_file->pfile, write_data, |
940 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1008 | to-from, &offset); |
941 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1009 | atomic_dec(&open_file->wrtPending); |
942 | if (open_file->closePend) | ||
943 | continue; | ||
944 | /* We check if file is open for writing first */ | ||
945 | if ((open_file->pfile) && | ||
946 | ((open_file->pfile->f_flags & O_RDWR) || | ||
947 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
948 | read_unlock(&GlobalSMBSeslock); | ||
949 | bytes_written = cifs_write(open_file->pfile, | ||
950 | write_data, to-from, | ||
951 | &offset); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* Does mm or vfs already set times? */ | 1010 | /* Does mm or vfs already set times? */ |
954 | inode->i_atime = | 1011 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
955 | inode->i_mtime = current_fs_time(inode->i_sb); | 1012 | if ((bytes_written > 0) && (offset)) { |
956 | if ((bytes_written > 0) && (offset)) { | 1013 | rc = 0; |
957 | rc = 0; | 1014 | } else if (bytes_written < 0) { |
958 | } else if (bytes_written < 0) { | 1015 | if (rc != -EBADF) |
959 | if (rc == -EBADF) { | 1016 | rc = bytes_written; |
960 | /* have seen a case in which kernel seemed to | ||
961 | have closed/freed a file even with writes | ||
962 | active so we might as well see if there are | ||
963 | other file structs to try for the same | ||
964 | inode before giving up */ | ||
965 | continue; | ||
966 | } else | ||
967 | rc = bytes_written; | ||
968 | } | ||
969 | break; /* now that we found a valid file handle and | ||
970 | tried to write to it we are done, no sense | ||
971 | continuing to loop looking for another */ | ||
972 | } | ||
973 | if (tmp->next == NULL) { | ||
974 | cFYI(1, ("File instance %p removed", tmp)); | ||
975 | break; | ||
976 | } | 1017 | } |
977 | } | 1018 | } else { |
978 | read_unlock(&GlobalSMBSeslock); | ||
979 | if (open_file == NULL) { | ||
980 | cFYI(1, ("No writeable filehandles for inode")); | 1019 | cFYI(1, ("No writeable filehandles for inode")); |
981 | rc = -EIO; | 1020 | rc = -EIO; |
982 | } | 1021 | } |
@@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
985 | return rc; | 1024 | return rc; |
986 | } | 1025 | } |
987 | 1026 | ||
988 | #if 0 | 1027 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
989 | static int cifs_writepages(struct address_space *mapping, | 1028 | static int cifs_writepages(struct address_space *mapping, |
990 | struct writeback_control *wbc) | 1029 | struct writeback_control *wbc) |
991 | { | 1030 | { |
992 | int rc = -EFAULT; | 1031 | struct backing_dev_info *bdi = mapping->backing_dev_info; |
1032 | unsigned int bytes_to_write; | ||
1033 | unsigned int bytes_written; | ||
1034 | struct cifs_sb_info *cifs_sb; | ||
1035 | int done = 0; | ||
1036 | pgoff_t end = -1; | ||
1037 | pgoff_t index; | ||
1038 | int is_range = 0; | ||
1039 | struct kvec iov[32]; | ||
1040 | int len; | ||
1041 | int n_iov = 0; | ||
1042 | pgoff_t next; | ||
1043 | int nr_pages; | ||
1044 | __u64 offset = 0; | ||
1045 | struct cifsFileInfo *open_file; | ||
1046 | struct page *page; | ||
1047 | struct pagevec pvec; | ||
1048 | int rc = 0; | ||
1049 | int scanned = 0; | ||
993 | int xid; | 1050 | int xid; |
994 | 1051 | ||
1052 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
1053 | |||
1054 | /* | ||
1055 | * If wsize is smaller that the page cache size, default to writing | ||
1056 | * one page at a time via cifs_writepage | ||
1057 | */ | ||
1058 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | ||
1059 | return generic_writepages(mapping, wbc); | ||
1060 | |||
1061 | /* BB FIXME we do not have code to sign across multiple buffers yet, | ||
1062 | so go to older writepage style write which we can sign if needed */ | ||
1063 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | ||
1064 | if(cifs_sb->tcon->ses->server->secMode & | ||
1065 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1066 | return generic_writepages(mapping, wbc); | ||
1067 | |||
1068 | /* | ||
1069 | * BB: Is this meaningful for a non-block-device file system? | ||
1070 | * If it is, we should test it again after we do I/O | ||
1071 | */ | ||
1072 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
1073 | wbc->encountered_congestion = 1; | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
995 | xid = GetXid(); | 1077 | xid = GetXid(); |
996 | 1078 | ||
997 | /* Find contiguous pages then iterate through repeating | 1079 | pagevec_init(&pvec, 0); |
998 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | 1080 | if (wbc->sync_mode == WB_SYNC_NONE) |
999 | support then send larger writes via kevec so as to eliminate | 1081 | index = mapping->writeback_index; /* Start from prev offset */ |
1000 | a memcpy */ | 1082 | else { |
1083 | index = 0; | ||
1084 | scanned = 1; | ||
1085 | } | ||
1086 | if (wbc->start || wbc->end) { | ||
1087 | index = wbc->start >> PAGE_CACHE_SHIFT; | ||
1088 | end = wbc->end >> PAGE_CACHE_SHIFT; | ||
1089 | is_range = 1; | ||
1090 | scanned = 1; | ||
1091 | } | ||
1092 | retry: | ||
1093 | while (!done && (index <= end) && | ||
1094 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
1095 | PAGECACHE_TAG_DIRTY, | ||
1096 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | ||
1097 | int first; | ||
1098 | unsigned int i; | ||
1099 | |||
1100 | first = -1; | ||
1101 | next = 0; | ||
1102 | n_iov = 0; | ||
1103 | bytes_to_write = 0; | ||
1104 | |||
1105 | for (i = 0; i < nr_pages; i++) { | ||
1106 | page = pvec.pages[i]; | ||
1107 | /* | ||
1108 | * At this point we hold neither mapping->tree_lock nor | ||
1109 | * lock on the page itself: the page may be truncated or | ||
1110 | * invalidated (changing page->mapping to NULL), or even | ||
1111 | * swizzled back from swapper_space to tmpfs file | ||
1112 | * mapping | ||
1113 | */ | ||
1114 | |||
1115 | if (first < 0) | ||
1116 | lock_page(page); | ||
1117 | else if (TestSetPageLocked(page)) | ||
1118 | break; | ||
1119 | |||
1120 | if (unlikely(page->mapping != mapping)) { | ||
1121 | unlock_page(page); | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | if (unlikely(is_range) && (page->index > end)) { | ||
1126 | done = 1; | ||
1127 | unlock_page(page); | ||
1128 | break; | ||
1129 | } | ||
1130 | |||
1131 | if (next && (page->index != next)) { | ||
1132 | /* Not next consecutive page */ | ||
1133 | unlock_page(page); | ||
1134 | break; | ||
1135 | } | ||
1136 | |||
1137 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1138 | wait_on_page_writeback(page); | ||
1139 | |||
1140 | if (PageWriteback(page) || | ||
1141 | !test_clear_page_dirty(page)) { | ||
1142 | unlock_page(page); | ||
1143 | break; | ||
1144 | } | ||
1145 | |||
1146 | if (page_offset(page) >= mapping->host->i_size) { | ||
1147 | done = 1; | ||
1148 | unlock_page(page); | ||
1149 | break; | ||
1150 | } | ||
1151 | |||
1152 | /* | ||
1153 | * BB can we get rid of this? pages are held by pvec | ||
1154 | */ | ||
1155 | page_cache_get(page); | ||
1156 | |||
1157 | len = min(mapping->host->i_size - page_offset(page), | ||
1158 | (loff_t)PAGE_CACHE_SIZE); | ||
1159 | |||
1160 | /* reserve iov[0] for the smb header */ | ||
1161 | n_iov++; | ||
1162 | iov[n_iov].iov_base = kmap(page); | ||
1163 | iov[n_iov].iov_len = len; | ||
1164 | bytes_to_write += len; | ||
1165 | |||
1166 | if (first < 0) { | ||
1167 | first = i; | ||
1168 | offset = page_offset(page); | ||
1169 | } | ||
1170 | next = page->index + 1; | ||
1171 | if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) | ||
1172 | break; | ||
1173 | } | ||
1174 | if (n_iov) { | ||
1175 | /* Search for a writable handle every time we call | ||
1176 | * CIFSSMBWrite2. We can't rely on the last handle | ||
1177 | * we used to still be valid | ||
1178 | */ | ||
1179 | open_file = find_writable_file(CIFS_I(mapping->host)); | ||
1180 | if (!open_file) { | ||
1181 | cERROR(1, ("No writable handles for inode")); | ||
1182 | rc = -EBADF; | ||
1183 | } else { | ||
1184 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | ||
1185 | open_file->netfid, | ||
1186 | bytes_to_write, offset, | ||
1187 | &bytes_written, iov, n_iov, | ||
1188 | 1); | ||
1189 | atomic_dec(&open_file->wrtPending); | ||
1190 | if (rc || bytes_written < bytes_to_write) { | ||
1191 | cERROR(1,("Write2 ret %d, written = %d", | ||
1192 | rc, bytes_written)); | ||
1193 | /* BB what if continued retry is | ||
1194 | requested via mount flags? */ | ||
1195 | set_bit(AS_EIO, &mapping->flags); | ||
1196 | SetPageError(page); | ||
1197 | } else { | ||
1198 | cifs_stats_bytes_written(cifs_sb->tcon, | ||
1199 | bytes_written); | ||
1200 | } | ||
1201 | } | ||
1202 | for (i = 0; i < n_iov; i++) { | ||
1203 | page = pvec.pages[first + i]; | ||
1204 | kunmap(page); | ||
1205 | unlock_page(page); | ||
1206 | page_cache_release(page); | ||
1207 | } | ||
1208 | if ((wbc->nr_to_write -= n_iov) <= 0) | ||
1209 | done = 1; | ||
1210 | index = next; | ||
1211 | } | ||
1212 | pagevec_release(&pvec); | ||
1213 | } | ||
1214 | if (!scanned && !done) { | ||
1215 | /* | ||
1216 | * We hit the last page and there is more work to be done: wrap | ||
1217 | * back to the start of the file | ||
1218 | */ | ||
1219 | scanned = 1; | ||
1220 | index = 0; | ||
1221 | goto retry; | ||
1222 | } | ||
1223 | if (!is_range) | ||
1224 | mapping->writeback_index = index; | ||
1225 | |||
1001 | FreeXid(xid); | 1226 | FreeXid(xid); |
1227 | |||
1002 | return rc; | 1228 | return rc; |
1003 | } | 1229 | } |
1004 | #endif | 1230 | #endif |
@@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1207 | if (rc != 0) | 1433 | if (rc != 0) |
1208 | break; | 1434 | break; |
1209 | } | 1435 | } |
1210 | |||
1211 | rc = CIFSSMBRead(xid, pTcon, | 1436 | rc = CIFSSMBRead(xid, pTcon, |
1212 | open_file->netfid, | 1437 | open_file->netfid, |
1213 | current_read_size, *poffset, | 1438 | current_read_size, *poffset, |
1214 | &bytes_read, &smb_read_data); | 1439 | &bytes_read, &smb_read_data); |
1215 | |||
1216 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1217 | if (copy_to_user(current_offset, | 1441 | if (copy_to_user(current_offset, |
1218 | smb_read_data + 4 /* RFC1001 hdr */ | 1442 | smb_read_data + 4 /* RFC1001 hdr */ |
@@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1235 | return rc; | 1459 | return rc; |
1236 | } | 1460 | } |
1237 | } else { | 1461 | } else { |
1238 | #ifdef CONFIG_CIFS_STATS | 1462 | cifs_stats_bytes_read(pTcon, bytes_read); |
1239 | atomic_inc(&pTcon->num_reads); | ||
1240 | spin_lock(&pTcon->stat_lock); | ||
1241 | pTcon->bytes_read += total_read; | ||
1242 | spin_unlock(&pTcon->stat_lock); | ||
1243 | #endif | ||
1244 | *poffset += bytes_read; | 1463 | *poffset += bytes_read; |
1245 | } | 1464 | } |
1246 | } | 1465 | } |
@@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1280 | total_read += bytes_read, current_offset += bytes_read) { | 1499 | total_read += bytes_read, current_offset += bytes_read) { |
1281 | current_read_size = min_t(const int, read_size - total_read, | 1500 | current_read_size = min_t(const int, read_size - total_read, |
1282 | cifs_sb->rsize); | 1501 | cifs_sb->rsize); |
1502 | /* For windows me and 9x we do not want to request more | ||
1503 | than it negotiated since it will refuse the read then */ | ||
1504 | if((pTcon->ses) && | ||
1505 | !(pTcon->ses->capabilities & CAP_LARGE_FILES)) { | ||
1506 | current_read_size = min_t(const int, current_read_size, | ||
1507 | pTcon->ses->server->maxBuf - 128); | ||
1508 | } | ||
1283 | rc = -EAGAIN; | 1509 | rc = -EAGAIN; |
1284 | while (rc == -EAGAIN) { | 1510 | while (rc == -EAGAIN) { |
1285 | if ((open_file->invalidHandle) && | 1511 | if ((open_file->invalidHandle) && |
@@ -1289,11 +1515,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1289 | if (rc != 0) | 1515 | if (rc != 0) |
1290 | break; | 1516 | break; |
1291 | } | 1517 | } |
1292 | |||
1293 | rc = CIFSSMBRead(xid, pTcon, | 1518 | rc = CIFSSMBRead(xid, pTcon, |
1294 | open_file->netfid, | 1519 | open_file->netfid, |
1295 | current_read_size, *poffset, | 1520 | current_read_size, *poffset, |
1296 | &bytes_read, ¤t_offset); | 1521 | &bytes_read, ¤t_offset); |
1297 | } | 1522 | } |
1298 | if (rc || (bytes_read == 0)) { | 1523 | if (rc || (bytes_read == 0)) { |
1299 | if (total_read) { | 1524 | if (total_read) { |
@@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1303 | return rc; | 1528 | return rc; |
1304 | } | 1529 | } |
1305 | } else { | 1530 | } else { |
1306 | #ifdef CONFIG_CIFS_STATS | 1531 | cifs_stats_bytes_read(pTcon, total_read); |
1307 | atomic_inc(&pTcon->num_reads); | ||
1308 | spin_lock(&pTcon->stat_lock); | ||
1309 | pTcon->bytes_read += total_read; | ||
1310 | spin_unlock(&pTcon->stat_lock); | ||
1311 | #endif | ||
1312 | *poffset += bytes_read; | 1532 | *poffset += bytes_read; |
1313 | } | 1533 | } |
1314 | } | 1534 | } |
@@ -1452,10 +1672,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1452 | } | 1672 | } |
1453 | 1673 | ||
1454 | rc = CIFSSMBRead(xid, pTcon, | 1674 | rc = CIFSSMBRead(xid, pTcon, |
1455 | open_file->netfid, | 1675 | open_file->netfid, |
1456 | read_size, offset, | 1676 | read_size, offset, |
1457 | &bytes_read, &smb_read_data); | 1677 | &bytes_read, &smb_read_data); |
1458 | /* BB need to check return code here */ | 1678 | |
1679 | /* BB more RC checks ? */ | ||
1459 | if (rc== -EAGAIN) { | 1680 | if (rc== -EAGAIN) { |
1460 | if (smb_read_data) { | 1681 | if (smb_read_data) { |
1461 | cifs_buf_release(smb_read_data); | 1682 | cifs_buf_release(smb_read_data); |
@@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1480 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | 1701 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); |
1481 | 1702 | ||
1482 | i += bytes_read >> PAGE_CACHE_SHIFT; | 1703 | i += bytes_read >> PAGE_CACHE_SHIFT; |
1483 | #ifdef CONFIG_CIFS_STATS | 1704 | cifs_stats_bytes_read(pTcon, bytes_read); |
1484 | atomic_inc(&pTcon->num_reads); | ||
1485 | spin_lock(&pTcon->stat_lock); | ||
1486 | pTcon->bytes_read += bytes_read; | ||
1487 | spin_unlock(&pTcon->stat_lock); | ||
1488 | #endif | ||
1489 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | 1705 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { |
1490 | i++; /* account for partial page */ | 1706 | i++; /* account for partial page */ |
1491 | 1707 | ||
@@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
1603 | page caching in the current Linux kernel design */ | 1819 | page caching in the current Linux kernel design */ |
1604 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | 1820 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) |
1605 | { | 1821 | { |
1606 | struct list_head *tmp; | ||
1607 | struct list_head *tmp1; | ||
1608 | struct cifsFileInfo *open_file = NULL; | 1822 | struct cifsFileInfo *open_file = NULL; |
1609 | int rc = TRUE; | ||
1610 | 1823 | ||
1611 | if (cifsInode == NULL) | 1824 | if (cifsInode) |
1612 | return rc; | 1825 | open_file = find_writable_file(cifsInode); |
1613 | 1826 | ||
1614 | read_lock(&GlobalSMBSeslock); | 1827 | if(open_file) { |
1615 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1828 | /* there is not actually a write pending so let |
1616 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1829 | this handle go free and allow it to |
1617 | if (open_file == NULL) | 1830 | be closable if needed */ |
1618 | break; | 1831 | atomic_dec(&open_file->wrtPending); |
1619 | if (open_file->closePend) | 1832 | return 0; |
1620 | continue; | 1833 | } else |
1621 | /* We check if file is open for writing, | 1834 | return 1; |
1622 | BB we could supplement this with a check to see if file size | ||
1623 | changes have been flushed to server - ie inode metadata dirty */ | ||
1624 | if ((open_file->pfile) && | ||
1625 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1626 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1627 | rc = FALSE; | ||
1628 | break; | ||
1629 | } | ||
1630 | if (tmp->next == NULL) { | ||
1631 | cFYI(1, ("File instance %p removed", tmp)); | ||
1632 | break; | ||
1633 | } | ||
1634 | } | ||
1635 | read_unlock(&GlobalSMBSeslock); | ||
1636 | return rc; | ||
1637 | } | 1835 | } |
1638 | 1836 | ||
1639 | |||
1640 | static int cifs_prepare_write(struct file *file, struct page *page, | 1837 | static int cifs_prepare_write(struct file *file, struct page *page, |
1641 | unsigned from, unsigned to) | 1838 | unsigned from, unsigned to) |
1642 | { | 1839 | { |
@@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = { | |||
1676 | .readpage = cifs_readpage, | 1873 | .readpage = cifs_readpage, |
1677 | .readpages = cifs_readpages, | 1874 | .readpages = cifs_readpages, |
1678 | .writepage = cifs_writepage, | 1875 | .writepage = cifs_writepage, |
1876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1877 | .writepages = cifs_writepages, | ||
1878 | #endif | ||
1679 | .prepare_write = cifs_prepare_write, | 1879 | .prepare_write = cifs_prepare_write, |
1680 | .commit_write = cifs_commit_write, | 1880 | .commit_write = cifs_commit_write, |
1681 | .set_page_dirty = __set_page_dirty_nobuffers, | 1881 | .set_page_dirty = __set_page_dirty_nobuffers, |