diff options
| -rw-r--r-- | fs/cifs/file.c | 241 |
1 files changed, 99 insertions, 142 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c672afef0c09..00b926ce7935 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -1092,58 +1092,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 1092 | static int cifs_writepages(struct address_space *mapping, | 1092 | static int cifs_writepages(struct address_space *mapping, |
| 1093 | struct writeback_control *wbc) | 1093 | struct writeback_control *wbc) |
| 1094 | { | 1094 | { |
| 1095 | unsigned int bytes_to_write; | 1095 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); |
| 1096 | unsigned int bytes_written; | 1096 | bool done = false, scanned = false, range_whole = false; |
| 1097 | struct cifs_sb_info *cifs_sb; | 1097 | pgoff_t end, index; |
| 1098 | int done = 0; | 1098 | struct cifs_writedata *wdata; |
| 1099 | pgoff_t end; | ||
| 1100 | pgoff_t index; | ||
| 1101 | int range_whole = 0; | ||
| 1102 | struct kvec *iov; | ||
| 1103 | int len; | ||
| 1104 | int n_iov = 0; | ||
| 1105 | pgoff_t next; | ||
| 1106 | int nr_pages; | ||
| 1107 | __u64 offset = 0; | ||
| 1108 | struct cifsFileInfo *open_file; | ||
| 1109 | struct cifsTconInfo *tcon; | ||
| 1110 | struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); | ||
| 1111 | struct page *page; | 1099 | struct page *page; |
| 1112 | struct pagevec pvec; | ||
| 1113 | int rc = 0; | 1100 | int rc = 0; |
| 1114 | int scanned = 0; | ||
| 1115 | int xid; | ||
| 1116 | |||
| 1117 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
| 1118 | 1101 | ||
| 1119 | /* | 1102 | /* |
| 1120 | * If wsize is smaller that the page cache size, default to writing | 1103 | * If wsize is smaller than the page cache size, default to writing |
| 1121 | * one page at a time via cifs_writepage | 1104 | * one page at a time via cifs_writepage |
| 1122 | */ | 1105 | */ |
| 1123 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | 1106 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) |
| 1124 | return generic_writepages(mapping, wbc); | 1107 | return generic_writepages(mapping, wbc); |
| 1125 | 1108 | ||
| 1126 | iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); | ||
| 1127 | if (iov == NULL) | ||
| 1128 | return generic_writepages(mapping, wbc); | ||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * if there's no open file, then this is likely to fail too, | ||
| 1132 | * but it'll at least handle the return. Maybe it should be | ||
| 1133 | * a BUG() instead? | ||
| 1134 | */ | ||
| 1135 | open_file = find_writable_file(CIFS_I(mapping->host), false); | ||
| 1136 | if (!open_file) { | ||
| 1137 | kfree(iov); | ||
| 1138 | return generic_writepages(mapping, wbc); | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | tcon = tlink_tcon(open_file->tlink); | ||
| 1142 | cifsFileInfo_put(open_file); | ||
| 1143 | |||
| 1144 | xid = GetXid(); | ||
| 1145 | |||
| 1146 | pagevec_init(&pvec, 0); | ||
| 1147 | if (wbc->range_cyclic) { | 1109 | if (wbc->range_cyclic) { |
| 1148 | index = mapping->writeback_index; /* Start from prev offset */ | 1110 | index = mapping->writeback_index; /* Start from prev offset */ |
| 1149 | end = -1; | 1111 | end = -1; |
| @@ -1151,24 +1113,49 @@ static int cifs_writepages(struct address_space *mapping, | |||
| 1151 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | 1113 | index = wbc->range_start >> PAGE_CACHE_SHIFT; |
| 1152 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1114 | end = wbc->range_end >> PAGE_CACHE_SHIFT; |
| 1153 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | 1115 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) |
| 1154 | range_whole = 1; | 1116 | range_whole = true; |
| 1155 | scanned = 1; | 1117 | scanned = true; |
| 1156 | } | 1118 | } |
| 1157 | retry: | 1119 | retry: |
| 1158 | while (!done && (index <= end) && | 1120 | while (!done && index <= end) { |
| 1159 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | 1121 | unsigned int i, nr_pages, found_pages; |
| 1160 | PAGECACHE_TAG_DIRTY, | 1122 | pgoff_t next = 0, tofind; |
| 1161 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | 1123 | struct page **pages; |
| 1162 | int first; | 1124 | |
| 1163 | unsigned int i; | 1125 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, |
| 1164 | 1126 | end - index) + 1; | |
| 1165 | first = -1; | 1127 | |
| 1166 | next = 0; | 1128 | wdata = cifs_writedata_alloc((unsigned int)tofind); |
| 1167 | n_iov = 0; | 1129 | if (!wdata) { |
| 1168 | bytes_to_write = 0; | 1130 | rc = -ENOMEM; |
| 1169 | 1131 | break; | |
| 1170 | for (i = 0; i < nr_pages; i++) { | 1132 | } |
| 1171 | page = pvec.pages[i]; | 1133 | |
| 1134 | /* | ||
| 1135 | * find_get_pages_tag seems to return a max of 256 on each | ||
| 1136 | * iteration, so we must call it several times in order to | ||
| 1137 | * fill the array or the wsize is effectively limited to | ||
| 1138 | * 256 * PAGE_CACHE_SIZE. | ||
| 1139 | */ | ||
| 1140 | found_pages = 0; | ||
| 1141 | pages = wdata->pages; | ||
| 1142 | do { | ||
| 1143 | nr_pages = find_get_pages_tag(mapping, &index, | ||
| 1144 | PAGECACHE_TAG_DIRTY, | ||
| 1145 | tofind, pages); | ||
| 1146 | found_pages += nr_pages; | ||
| 1147 | tofind -= nr_pages; | ||
| 1148 | pages += nr_pages; | ||
| 1149 | } while (nr_pages && tofind && index <= end); | ||
| 1150 | |||
| 1151 | if (found_pages == 0) { | ||
| 1152 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
| 1153 | break; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | nr_pages = 0; | ||
| 1157 | for (i = 0; i < found_pages; i++) { | ||
| 1158 | page = wdata->pages[i]; | ||
| 1172 | /* | 1159 | /* |
| 1173 | * At this point we hold neither mapping->tree_lock nor | 1160 | * At this point we hold neither mapping->tree_lock nor |
| 1174 | * lock on the page itself: the page may be truncated or | 1161 | * lock on the page itself: the page may be truncated or |
| @@ -1177,7 +1164,7 @@ retry: | |||
| 1177 | * mapping | 1164 | * mapping |
| 1178 | */ | 1165 | */ |
| 1179 | 1166 | ||
| 1180 | if (first < 0) | 1167 | if (nr_pages == 0) |
| 1181 | lock_page(page); | 1168 | lock_page(page); |
| 1182 | else if (!trylock_page(page)) | 1169 | else if (!trylock_page(page)) |
| 1183 | break; | 1170 | break; |
| @@ -1188,7 +1175,7 @@ retry: | |||
| 1188 | } | 1175 | } |
| 1189 | 1176 | ||
| 1190 | if (!wbc->range_cyclic && page->index > end) { | 1177 | if (!wbc->range_cyclic && page->index > end) { |
| 1191 | done = 1; | 1178 | done = true; |
| 1192 | unlock_page(page); | 1179 | unlock_page(page); |
| 1193 | break; | 1180 | break; |
| 1194 | } | 1181 | } |
| @@ -1215,119 +1202,89 @@ retry: | |||
| 1215 | set_page_writeback(page); | 1202 | set_page_writeback(page); |
| 1216 | 1203 | ||
| 1217 | if (page_offset(page) >= mapping->host->i_size) { | 1204 | if (page_offset(page) >= mapping->host->i_size) { |
| 1218 | done = 1; | 1205 | done = true; |
| 1219 | unlock_page(page); | 1206 | unlock_page(page); |
| 1220 | end_page_writeback(page); | 1207 | end_page_writeback(page); |
| 1221 | break; | 1208 | break; |
| 1222 | } | 1209 | } |
| 1223 | 1210 | ||
| 1224 | /* | 1211 | wdata->pages[i] = page; |
| 1225 | * BB can we get rid of this? pages are held by pvec | 1212 | next = page->index + 1; |
| 1226 | */ | 1213 | ++nr_pages; |
| 1227 | page_cache_get(page); | 1214 | } |
| 1228 | 1215 | ||
| 1229 | len = min(mapping->host->i_size - page_offset(page), | 1216 | /* reset index to refind any pages skipped */ |
| 1230 | (loff_t)PAGE_CACHE_SIZE); | 1217 | if (nr_pages == 0) |
| 1218 | index = wdata->pages[0]->index + 1; | ||
| 1231 | 1219 | ||
| 1232 | /* reserve iov[0] for the smb header */ | 1220 | /* put any pages we aren't going to use */ |
| 1233 | n_iov++; | 1221 | for (i = nr_pages; i < found_pages; i++) { |
| 1234 | iov[n_iov].iov_base = kmap(page); | 1222 | page_cache_release(wdata->pages[i]); |
| 1235 | iov[n_iov].iov_len = len; | 1223 | wdata->pages[i] = NULL; |
| 1236 | bytes_to_write += len; | 1224 | } |
| 1237 | 1225 | ||
| 1238 | if (first < 0) { | 1226 | /* nothing to write? */ |
| 1239 | first = i; | 1227 | if (nr_pages == 0) { |
| 1240 | offset = page_ | ||
