diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c new file mode 100644 index 000000000000..dcab7cf1b53b --- /dev/null +++ b/fs/cifs/file.c | |||
@@ -0,0 +1,1675 @@ | |||
1 | /* | ||
2 | * fs/cifs/file.c | ||
3 | * | ||
4 | * vfs operations that deal with files | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/stat.h> | ||
25 | #include <linux/fcntl.h> | ||
26 | #include <linux/pagemap.h> | ||
27 | #include <linux/pagevec.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <asm/div64.h> | ||
30 | #include "cifsfs.h" | ||
31 | #include "cifspdu.h" | ||
32 | #include "cifsglob.h" | ||
33 | #include "cifsproto.h" | ||
34 | #include "cifs_unicode.h" | ||
35 | #include "cifs_debug.h" | ||
36 | #include "cifs_fs_sb.h" | ||
37 | |||
38 | static inline struct cifsFileInfo *cifs_init_private( | ||
39 | struct cifsFileInfo *private_data, struct inode *inode, | ||
40 | struct file *file, __u16 netfid) | ||
41 | { | ||
42 | memset(private_data, 0, sizeof(struct cifsFileInfo)); | ||
43 | private_data->netfid = netfid; | ||
44 | private_data->pid = current->tgid; | ||
45 | init_MUTEX(&private_data->fh_sem); | ||
46 | private_data->pfile = file; /* needed for writepage */ | ||
47 | private_data->pInode = inode; | ||
48 | private_data->invalidHandle = FALSE; | ||
49 | private_data->closePend = FALSE; | ||
50 | |||
51 | return private_data; | ||
52 | } | ||
53 | |||
54 | static inline int cifs_convert_flags(unsigned int flags) | ||
55 | { | ||
56 | if ((flags & O_ACCMODE) == O_RDONLY) | ||
57 | return GENERIC_READ; | ||
58 | else if ((flags & O_ACCMODE) == O_WRONLY) | ||
59 | return GENERIC_WRITE; | ||
60 | else if ((flags & O_ACCMODE) == O_RDWR) { | ||
61 | /* GENERIC_ALL is too much permission to request | ||
62 | can cause unnecessary access denied on create */ | ||
63 | /* return GENERIC_ALL; */ | ||
64 | return (GENERIC_READ | GENERIC_WRITE); | ||
65 | } | ||
66 | |||
67 | return 0x20197; | ||
68 | } | ||
69 | |||
70 | static inline int cifs_get_disposition(unsigned int flags) | ||
71 | { | ||
72 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
73 | return FILE_CREATE; | ||
74 | else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
75 | return FILE_OVERWRITE_IF; | ||
76 | else if ((flags & O_CREAT) == O_CREAT) | ||
77 | return FILE_OPEN_IF; | ||
78 | else | ||
79 | return FILE_OPEN; | ||
80 | } | ||
81 | |||
82 | /* all arguments to this function must be checked for validity in caller */ | ||
83 | static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | ||
84 | struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, | ||
85 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, | ||
86 | char *full_path, int xid) | ||
87 | { | ||
88 | struct timespec temp; | ||
89 | int rc; | ||
90 | |||
91 | /* want handles we can use to read with first | ||
92 | in the list so we do not have to walk the | ||
93 | list to search for one in prepare_write */ | ||
94 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
95 | list_add_tail(&pCifsFile->flist, | ||
96 | &pCifsInode->openFileList); | ||
97 | } else { | ||
98 | list_add(&pCifsFile->flist, | ||
99 | &pCifsInode->openFileList); | ||
100 | } | ||
101 | write_unlock(&GlobalSMBSeslock); | ||
102 | write_unlock(&file->f_owner.lock); | ||
103 | if (pCifsInode->clientCanCacheRead) { | ||
104 | /* we have the inode open somewhere else | ||
105 | no need to discard cache data */ | ||
106 | goto client_can_cache; | ||
107 | } | ||
108 | |||
109 | /* BB need same check in cifs_create too? */ | ||
110 | /* if not oplocked, invalidate inode pages if mtime or file | ||
111 | size changed */ | ||
112 | temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); | ||
113 | if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) && | ||
114 | (file->f_dentry->d_inode->i_size == | ||
115 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | ||
116 | cFYI(1, ("inode unchanged on server")); | ||
117 | } else { | ||
118 | if (file->f_dentry->d_inode->i_mapping) { | ||
119 | /* BB no need to lock inode until after invalidate | ||
120 | since namei code should already have it locked? */ | ||
121 | filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); | ||
122 | filemap_fdatawait(file->f_dentry->d_inode->i_mapping); | ||
123 | } | ||
124 | cFYI(1, ("invalidating remote inode since open detected it " | ||
125 | "changed")); | ||
126 | invalidate_remote_inode(file->f_dentry->d_inode); | ||
127 | } | ||
128 | |||
129 | client_can_cache: | ||
130 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
131 | rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, | ||
132 | full_path, inode->i_sb, xid); | ||
133 | else | ||
134 | rc = cifs_get_inode_info(&file->f_dentry->d_inode, | ||
135 | full_path, buf, inode->i_sb, xid); | ||
136 | |||
137 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
138 | pCifsInode->clientCanCacheAll = TRUE; | ||
139 | pCifsInode->clientCanCacheRead = TRUE; | ||
140 | cFYI(1, ("Exclusive Oplock granted on inode %p", | ||
141 | file->f_dentry->d_inode)); | ||
142 | } else if ((*oplock & 0xF) == OPLOCK_READ) | ||
143 | pCifsInode->clientCanCacheRead = TRUE; | ||
144 | |||
145 | return rc; | ||
146 | } | ||
147 | |||
148 | int cifs_open(struct inode *inode, struct file *file) | ||
149 | { | ||
150 | int rc = -EACCES; | ||
151 | int xid, oplock; | ||
152 | struct cifs_sb_info *cifs_sb; | ||
153 | struct cifsTconInfo *pTcon; | ||
154 | struct cifsFileInfo *pCifsFile; | ||
155 | struct cifsInodeInfo *pCifsInode; | ||
156 | struct list_head *tmp; | ||
157 | char *full_path = NULL; | ||
158 | int desiredAccess; | ||
159 | int disposition; | ||
160 | __u16 netfid; | ||
161 | FILE_ALL_INFO *buf = NULL; | ||
162 | |||
163 | xid = GetXid(); | ||
164 | |||
165 | cifs_sb = CIFS_SB(inode->i_sb); | ||
166 | pTcon = cifs_sb->tcon; | ||
167 | |||
168 | if (file->f_flags & O_CREAT) { | ||
169 | /* search inode for this file and fill in file->private_data */ | ||
170 | pCifsInode = CIFS_I(file->f_dentry->d_inode); | ||
171 | read_lock(&GlobalSMBSeslock); | ||
172 | list_for_each(tmp, &pCifsInode->openFileList) { | ||
173 | pCifsFile = list_entry(tmp, struct cifsFileInfo, | ||
174 | flist); | ||
175 | if ((pCifsFile->pfile == NULL) && | ||
176 | (pCifsFile->pid == current->tgid)) { | ||
177 | /* mode set in cifs_create */ | ||
178 | |||
179 | /* needed for writepage */ | ||
180 | pCifsFile->pfile = file; | ||
181 | |||
182 | file->private_data = pCifsFile; | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | read_unlock(&GlobalSMBSeslock); | ||
187 | if (file->private_data != NULL) { | ||
188 | rc = 0; | ||
189 | FreeXid(xid); | ||
190 | return rc; | ||
191 | } else { | ||
192 | if (file->f_flags & O_EXCL) | ||
193 | cERROR(1, ("could not find file instance for " | ||
194 | "new file %p ", file)); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | down(&inode->i_sb->s_vfs_rename_sem); | ||
199 | full_path = build_path_from_dentry(file->f_dentry); | ||
200 | up(&inode->i_sb->s_vfs_rename_sem); | ||
201 | if (full_path == NULL) { | ||
202 | FreeXid(xid); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | |||
206 | cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", | ||
207 | inode, file->f_flags, full_path)); | ||
208 | desiredAccess = cifs_convert_flags(file->f_flags); | ||
209 | |||
210 | /********************************************************************* | ||
211 | * open flag mapping table: | ||
212 | * | ||
213 | * POSIX Flag CIFS Disposition | ||
214 | * ---------- ---------------- | ||
215 | * O_CREAT FILE_OPEN_IF | ||
216 | * O_CREAT | O_EXCL FILE_CREATE | ||
217 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
218 | * O_TRUNC FILE_OVERWRITE | ||
219 | * none of the above FILE_OPEN | ||
220 | * | ||
221 | * Note that there is not a direct match between disposition | ||
222 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
223 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
224 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
225 | * (which uses the attributes / metadata passed in on open call) | ||
226 | *? | ||
227 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
228 | *? and the read write flags match reasonably. O_LARGEFILE | ||
229 | *? is irrelevant because largefile support is always used | ||
230 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
231 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
232 | *********************************************************************/ | ||
233 | |||
234 | disposition = cifs_get_disposition(file->f_flags); | ||
235 | |||
236 | if (oplockEnabled) | ||
237 | oplock = REQ_OPLOCK; | ||
238 | else | ||
239 | oplock = FALSE; | ||
240 | |||
241 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
242 | |||
243 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | ||
244 | and calling get_inode_info with returned buf (at least helps | ||
245 | non-Unix server case) */ | ||
246 | |||
247 | /* BB we can not do this if this is the second open of a file | ||
248 | and the first handle has writebehind data, we might be | ||
249 | able to simply do a filemap_fdatawrite/filemap_fdatawait first */ | ||
250 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
251 | if (!buf) { | ||
252 | rc = -ENOMEM; | ||
253 | goto out; | ||
254 | } | ||
255 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, | ||
256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
257 | cifs_sb->local_nls); | ||
258 | if (rc) { | ||
259 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | ||
260 | goto out; | ||
261 | } | ||
262 | file->private_data = | ||
263 | kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
264 | if (file->private_data == NULL) { | ||
265 | rc = -ENOMEM; | ||
266 | goto out; | ||
267 | } | ||
268 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | ||
269 | write_lock(&file->f_owner.lock); | ||
270 | write_lock(&GlobalSMBSeslock); | ||
271 | list_add(&pCifsFile->tlist, &pTcon->openFileList); | ||
272 | |||
273 | pCifsInode = CIFS_I(file->f_dentry->d_inode); | ||
274 | if (pCifsInode) { | ||
275 | rc = cifs_open_inode_helper(inode, file, pCifsInode, | ||
276 | pCifsFile, pTcon, | ||
277 | &oplock, buf, full_path, xid); | ||
278 | } else { | ||
279 | write_unlock(&GlobalSMBSeslock); | ||
280 | write_unlock(&file->f_owner.lock); | ||
281 | } | ||
282 | |||
283 | if (oplock & CIFS_CREATE_ACTION) { | ||
284 | /* time to set mode which we can not set earlier due to | ||
285 | problems creating new read-only files */ | ||
286 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { | ||
287 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | ||
288 | inode->i_mode, | ||
289 | (__u64)-1, (__u64)-1, 0 /* dev */, | ||
290 | cifs_sb->local_nls); | ||
291 | } else { | ||
292 | /* BB implement via Windows security descriptors eg | ||
293 | CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, | ||
294 | -1, -1, local_nls); | ||
295 | in the meantime could set r/o dos attribute when | ||
296 | perms are eg: mode & 0222 == 0 */ | ||
297 | } | ||
298 | } | ||
299 | |||
300 | out: | ||
301 | kfree(buf); | ||
302 | kfree(full_path); | ||
303 | FreeXid(xid); | ||
304 | return rc; | ||
305 | } | ||
306 | |||
307 | /* Try to reaquire byte range locks that were released when session */ | ||
308 | /* to server was lost */ | ||
309 | static int cifs_relock_file(struct cifsFileInfo *cifsFile) | ||
310 | { | ||
311 | int rc = 0; | ||
312 | |||
313 | /* BB list all locks open on this file and relock */ | ||
314 | |||
315 | return rc; | ||
316 | } | ||
317 | |||
318 | static int cifs_reopen_file(struct inode *inode, struct file *file, | ||
319 | int can_flush) | ||
320 | { | ||
321 | int rc = -EACCES; | ||
322 | int xid, oplock; | ||
323 | struct cifs_sb_info *cifs_sb; | ||
324 | struct cifsTconInfo *pTcon; | ||
325 | struct cifsFileInfo *pCifsFile; | ||
326 | struct cifsInodeInfo *pCifsInode; | ||
327 | char *full_path = NULL; | ||
328 | int desiredAccess; | ||
329 | int disposition = FILE_OPEN; | ||
330 | __u16 netfid; | ||
331 | |||
332 | if (inode == NULL) | ||
333 | return -EBADF; | ||
334 | if (file->private_data) { | ||
335 | pCifsFile = (struct cifsFileInfo *)file->private_data; | ||
336 | } else | ||
337 | return -EBADF; | ||
338 | |||
339 | xid = GetXid(); | ||
340 | down(&pCifsFile->fh_sem); | ||
341 | if (pCifsFile->invalidHandle == FALSE) { | ||
342 | up(&pCifsFile->fh_sem); | ||
343 | FreeXid(xid); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | if (file->f_dentry == NULL) { | ||
348 | up(&pCifsFile->fh_sem); | ||
349 | cFYI(1, ("failed file reopen, no valid name if dentry freed")); | ||
350 | FreeXid(xid); | ||
351 | return -EBADF; | ||
352 | } | ||
353 | cifs_sb = CIFS_SB(inode->i_sb); | ||
354 | pTcon = cifs_sb->tcon; | ||
355 | /* can not grab rename sem here because various ops, including | ||
356 | those that already have the rename sem can end up causing writepage | ||
357 | to get called and if the server was down that means we end up here, | ||
358 | and we can never tell if the caller already has the rename_sem */ | ||
359 | full_path = build_path_from_dentry(file->f_dentry); | ||
360 | if (full_path == NULL) { | ||
361 | up(&pCifsFile->fh_sem); | ||
362 | FreeXid(xid); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", | ||
367 | inode, file->f_flags,full_path)); | ||
368 | desiredAccess = cifs_convert_flags(file->f_flags); | ||
369 | |||
370 | if (oplockEnabled) | ||
371 | oplock = REQ_OPLOCK; | ||
372 | else | ||
373 | oplock = FALSE; | ||
374 | |||
375 | /* Can not refresh inode by passing in file_info buf to be returned | ||
376 | by SMBOpen and then calling get_inode_info with returned buf | ||
377 | since file might have write behind data that needs to be flushed | ||
378 | and server version of file size can be stale. If we knew for sure | ||
379 | that inode was not dirty locally we could do this */ | ||
380 | |||
381 | /* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
382 | if (buf == 0) { | ||
383 | up(&pCifsFile->fh_sem); | ||
384 | kfree(full_path); | ||
385 | FreeXid(xid); | ||
386 | return -ENOMEM; | ||
387 | } */ | ||
388 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, | ||
389 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
390 | cifs_sb->local_nls); | ||
391 | if (rc) { | ||
392 | up(&pCifsFile->fh_sem); | ||
393 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | ||
394 | cFYI(1, ("oplock: %d ", oplock)); | ||
395 | } else { | ||
396 | pCifsFile->netfid = netfid; | ||
397 | pCifsFile->invalidHandle = FALSE; | ||
398 | up(&pCifsFile->fh_sem); | ||
399 | pCifsInode = CIFS_I(inode); | ||
400 | if (pCifsInode) { | ||
401 | if (can_flush) { | ||
402 | filemap_fdatawrite(inode->i_mapping); | ||
403 | filemap_fdatawait(inode->i_mapping); | ||
404 | /* temporarily disable caching while we | ||
405 | go to server to get inode info */ | ||
406 | pCifsInode->clientCanCacheAll = FALSE; | ||
407 | pCifsInode->clientCanCacheRead = FALSE; | ||
408 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
409 | rc = cifs_get_inode_info_unix(&inode, | ||
410 | full_path, inode->i_sb, xid); | ||
411 | else | ||
412 | rc = cifs_get_inode_info(&inode, | ||
413 | full_path, NULL, inode->i_sb, | ||
414 | xid); | ||
415 | } /* else we are writing out data to server already | ||
416 | and could deadlock if we tried to flush data, and | ||
417 | since we do not know if we have data that would | ||
418 | invalidate the current end of file on the server | ||
419 | we can not go to the server to get the new inod | ||
420 | info */ | ||
421 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
422 | pCifsInode->clientCanCacheAll = TRUE; | ||
423 | pCifsInode->clientCanCacheRead = TRUE; | ||
424 | cFYI(1, ("Exclusive Oplock granted on inode %p", | ||
425 | file->f_dentry->d_inode)); | ||
426 | } else if ((oplock & 0xF) == OPLOCK_READ) { | ||
427 | pCifsInode->clientCanCacheRead = TRUE; | ||
428 | pCifsInode->clientCanCacheAll = FALSE; | ||
429 | } else { | ||
430 | pCifsInode->clientCanCacheRead = FALSE; | ||
431 | pCifsInode->clientCanCacheAll = FALSE; | ||
432 | } | ||
433 | cifs_relock_file(pCifsFile); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | kfree(full_path); | ||
438 | FreeXid(xid); | ||
439 | return rc; | ||
440 | } | ||
441 | |||
442 | int cifs_close(struct inode *inode, struct file *file) | ||
443 | { | ||
444 | int rc = 0; | ||
445 | int xid; | ||
446 | struct cifs_sb_info *cifs_sb; | ||
447 | struct cifsTconInfo *pTcon; | ||
448 | struct cifsFileInfo *pSMBFile = | ||
449 | (struct cifsFileInfo *)file->private_data; | ||
450 | |||
451 | xid = GetXid(); | ||
452 | |||
453 | cifs_sb = CIFS_SB(inode->i_sb); | ||
454 | pTcon = cifs_sb->tcon; | ||
455 | if (pSMBFile) { | ||
456 | pSMBFile->closePend = TRUE; | ||
457 | write_lock(&file->f_owner.lock); | ||
458 | if (pTcon) { | ||
459 | /* no sense reconnecting to close a file that is | ||
460 | already closed */ | ||
461 | if (pTcon->tidStatus != CifsNeedReconnect) { | ||
462 | write_unlock(&file->f_owner.lock); | ||
463 | rc = CIFSSMBClose(xid, pTcon, | ||
464 | pSMBFile->netfid); | ||
465 | write_lock(&file->f_owner.lock); | ||
466 | } | ||
467 | } | ||
468 | list_del(&pSMBFile->flist); | ||
469 | list_del(&pSMBFile->tlist); | ||
470 | write_unlock(&file->f_owner.lock); | ||
471 | kfree(pSMBFile->search_resume_name); | ||
472 | kfree(file->private_data); | ||
473 | file->private_data = NULL; | ||
474 | } else | ||
475 | rc = -EBADF; | ||
476 | |||
477 | if (list_empty(&(CIFS_I(inode)->openFileList))) { | ||
478 | cFYI(1, ("closing last open instance for inode %p", inode)); | ||
479 | /* if the file is not open we do not know if we can cache info | ||
480 | on this inode, much less write behind and read ahead */ | ||
481 | CIFS_I(inode)->clientCanCacheRead = FALSE; | ||
482 | CIFS_I(inode)->clientCanCacheAll = FALSE; | ||
483 | } | ||
484 | if ((rc ==0) && CIFS_I(inode)->write_behind_rc) | ||
485 | rc = CIFS_I(inode)->write_behind_rc; | ||
486 | FreeXid(xid); | ||
487 | return rc; | ||
488 | } | ||
489 | |||
490 | int cifs_closedir(struct inode *inode, struct file *file) | ||
491 | { | ||
492 | int rc = 0; | ||
493 | int xid; | ||
494 | struct cifsFileInfo *pCFileStruct = | ||
495 | (struct cifsFileInfo *)file->private_data; | ||
496 | char *ptmp; | ||
497 | |||
498 | cFYI(1, ("Closedir inode = 0x%p with ", inode)); | ||
499 | |||
500 | xid = GetXid(); | ||
501 | |||
502 | if (pCFileStruct) { | ||
503 | struct cifsTconInfo *pTcon; | ||
504 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
505 | |||
506 | pTcon = cifs_sb->tcon; | ||
507 | |||
508 | cFYI(1, ("Freeing private data in close dir")); | ||
509 | if (pCFileStruct->srch_inf.endOfSearch == FALSE) { | ||
510 | pCFileStruct->invalidHandle = TRUE; | ||
511 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | ||
512 | cFYI(1, ("Closing uncompleted readdir with rc %d", | ||
513 | rc)); | ||
514 | /* not much we can do if it fails anyway, ignore rc */ | ||
515 | rc = 0; | ||
516 | } | ||
517 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | ||
518 | if (ptmp) { | ||
519 | /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); | ||
520 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; | ||
521 | cifs_buf_release(ptmp); | ||
522 | } | ||
523 | ptmp = pCFileStruct->search_resume_name; | ||
524 | if (ptmp) { | ||
525 | /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); | ||
526 | pCFileStruct->search_resume_name = NULL; | ||
527 | kfree(ptmp); | ||
528 | } | ||
529 | kfree(file->private_data); | ||
530 | file->private_data = NULL; | ||
531 | } | ||
532 | /* BB can we lock the filestruct while this is going on? */ | ||
533 | FreeXid(xid); | ||
534 | return rc; | ||
535 | } | ||
536 | |||
537 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | ||
538 | { | ||
539 | int rc, xid; | ||
540 | __u32 lockType = LOCKING_ANDX_LARGE_FILES; | ||
541 | __u32 numLock = 0; | ||
542 | __u32 numUnlock = 0; | ||
543 | __u64 length; | ||
544 | int wait_flag = FALSE; | ||
545 | struct cifs_sb_info *cifs_sb; | ||
546 | struct cifsTconInfo *pTcon; | ||
547 | |||
548 | length = 1 + pfLock->fl_end - pfLock->fl_start; | ||
549 | rc = -EACCES; | ||
550 | xid = GetXid(); | ||
551 | |||
552 | cFYI(1, ("Lock parm: 0x%x flockflags: " | ||
553 | "0x%x flocktype: 0x%x start: %lld end: %lld", | ||
554 | cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, | ||
555 | pfLock->fl_end)); | ||
556 | |||
557 | if (pfLock->fl_flags & FL_POSIX) | ||
558 | cFYI(1, ("Posix ")); | ||
559 | if (pfLock->fl_flags & FL_FLOCK) | ||
560 | cFYI(1, ("Flock ")); | ||
561 | if (pfLock->fl_flags & FL_SLEEP) { | ||
562 | cFYI(1, ("Blocking lock ")); | ||
563 | wait_flag = TRUE; | ||
564 | } | ||
565 | if (pfLock->fl_flags & FL_ACCESS) | ||
566 | cFYI(1, ("Process suspended by mandatory locking - " | ||
567 | "not implemented yet ")); | ||
568 | if (pfLock->fl_flags & FL_LEASE) | ||
569 | cFYI(1, ("Lease on file - not implemented yet")); | ||
570 | if (pfLock->fl_flags & | ||
571 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) | ||
572 | cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags)); | ||
573 | |||
574 | if (pfLock->fl_type == F_WRLCK) { | ||
575 | cFYI(1, ("F_WRLCK ")); | ||
576 | numLock = 1; | ||
577 | } else if (pfLock->fl_type == F_UNLCK) { | ||
578 | cFYI(1, ("F_UNLCK ")); | ||
579 | numUnlock = 1; | ||
580 | } else if (pfLock->fl_type == F_RDLCK) { | ||
581 | cFYI(1, ("F_RDLCK ")); | ||
582 | lockType |= LOCKING_ANDX_SHARED_LOCK; | ||
583 | numLock = 1; | ||
584 | } else if (pfLock->fl_type == F_EXLCK) { | ||
585 | cFYI(1, ("F_EXLCK ")); | ||
586 | numLock = 1; | ||
587 | } else if (pfLock->fl_type == F_SHLCK) { | ||
588 | cFYI(1, ("F_SHLCK ")); | ||
589 | lockType |= LOCKING_ANDX_SHARED_LOCK; | ||
590 | numLock = 1; | ||
591 | } else | ||
592 | cFYI(1, ("Unknown type of lock ")); | ||
593 | |||
594 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
595 | pTcon = cifs_sb->tcon; | ||
596 | |||
597 | if (file->private_data == NULL) { | ||
598 | FreeXid(xid); | ||
599 | return -EBADF; | ||
600 | } | ||
601 | |||
602 | if (IS_GETLK(cmd)) { | ||
603 | rc = CIFSSMBLock(xid, pTcon, | ||
604 | ((struct cifsFileInfo *)file-> | ||
605 | private_data)->netfid, | ||
606 | length, | ||
607 | pfLock->fl_start, 0, 1, lockType, | ||
608 | 0 /* wait flag */ ); | ||
609 | if (rc == 0) { | ||
610 | rc = CIFSSMBLock(xid, pTcon, | ||
611 | ((struct cifsFileInfo *) file-> | ||
612 | private_data)->netfid, | ||
613 | length, | ||
614 | pfLock->fl_start, 1 /* numUnlock */ , | ||
615 | 0 /* numLock */ , lockType, | ||
616 | 0 /* wait flag */ ); | ||
617 | pfLock->fl_type = F_UNLCK; | ||
618 | if (rc != 0) | ||
619 | cERROR(1, ("Error unlocking previously locked " | ||
620 | "range %d during test of lock ", | ||
621 | rc)); | ||
622 | rc = 0; | ||
623 | |||
624 | } else { | ||
625 | /* if rc == ERR_SHARING_VIOLATION ? */ | ||
626 | rc = 0; /* do not change lock type to unlock | ||
627 | since range in use */ | ||
628 | } | ||
629 | |||
630 | FreeXid(xid); | ||
631 | return rc; | ||
632 | } | ||
633 | |||
634 | rc = CIFSSMBLock(xid, pTcon, | ||
635 | ((struct cifsFileInfo *) file->private_data)-> | ||
636 | netfid, length, | ||
637 | pfLock->fl_start, numUnlock, numLock, lockType, | ||
638 | wait_flag); | ||
639 | if (rc == 0 && (pfLock->fl_flags & FL_POSIX)) | ||
640 | posix_lock_file_wait(file, pfLock); | ||
641 | FreeXid(xid); | ||
642 | return rc; | ||
643 | } | ||
644 | |||
645 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | ||
646 | size_t write_size, loff_t *poffset) | ||
647 | { | ||
648 | int rc = 0; | ||
649 | unsigned int bytes_written = 0; | ||
650 | unsigned int total_written; | ||
651 | struct cifs_sb_info *cifs_sb; | ||
652 | struct cifsTconInfo *pTcon; | ||
653 | int xid, long_op; | ||
654 | struct cifsFileInfo *open_file; | ||
655 | |||
656 | if (file->f_dentry == NULL) | ||
657 | return -EBADF; | ||
658 | |||
659 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
660 | if (cifs_sb == NULL) | ||
661 | return -EBADF; | ||
662 | |||
663 | pTcon = cifs_sb->tcon; | ||
664 | |||
665 | /* cFYI(1, | ||
666 | (" write %d bytes to offset %lld of %s", write_size, | ||
667 | *poffset, file->f_dentry->d_name.name)); */ | ||
668 | |||
669 | if (file->private_data == NULL) | ||
670 | return -EBADF; | ||
671 | else | ||
672 | open_file = (struct cifsFileInfo *) file->private_data; | ||
673 | |||
674 | xid = GetXid(); | ||
675 | if (file->f_dentry->d_inode == NULL) { | ||
676 | FreeXid(xid); | ||
677 | return -EBADF; | ||
678 | } | ||
679 | |||
680 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
681 | long_op = 2; /* writes past end of file can take a long time */ | ||
682 | else | ||
683 | long_op = 1; | ||
684 | |||
685 | for (total_written = 0; write_size > total_written; | ||
686 | total_written += bytes_written) { | ||
687 | rc = -EAGAIN; | ||
688 | while (rc == -EAGAIN) { | ||
689 | if (file->private_data == NULL) { | ||
690 | /* file has been closed on us */ | ||
691 | FreeXid(xid); | ||
692 | /* if we have gotten here we have written some data | ||
693 | and blocked, and the file has been freed on us while | ||
694 | we blocked so return what we managed to write */ | ||
695 | return total_written; | ||
696 | } | ||
697 | if (open_file->closePend) { | ||
698 | FreeXid(xid); | ||
699 | if (total_written) | ||
700 | return total_written; | ||
701 | else | ||
702 | return -EBADF; | ||
703 | } | ||
704 | if (open_file->invalidHandle) { | ||
705 | if ((file->f_dentry == NULL) || | ||
706 | (file->f_dentry->d_inode == NULL)) { | ||
707 | FreeXid(xid); | ||
708 | return total_written; | ||
709 | } | ||
710 | /* we could deadlock if we called | ||
711 | filemap_fdatawait from here so tell | ||
712 | reopen_file not to flush data to server | ||
713 | now */ | ||
714 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
715 | file, FALSE); | ||
716 | if (rc != 0) | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | rc = CIFSSMBWrite(xid, pTcon, | ||
721 | open_file->netfid, | ||
722 | min_t(const int, cifs_sb->wsize, | ||
723 | write_size - total_written), | ||
724 | *poffset, &bytes_written, | ||
725 | NULL, write_data + total_written, long_op); | ||
726 | } | ||
727 | if (rc || (bytes_written == 0)) { | ||
728 | if (total_written) | ||
729 | break; | ||
730 | else { | ||
731 | FreeXid(xid); | ||
732 | return rc; | ||
733 | } | ||
734 | } else | ||
735 | *poffset += bytes_written; | ||
736 | long_op = FALSE; /* subsequent writes fast - | ||
737 | 15 seconds is plenty */ | ||
738 | } | ||
739 | |||
740 | #ifdef CONFIG_CIFS_STATS | ||
741 | if (total_written > 0) { | ||
742 | atomic_inc(&pTcon->num_writes); | ||
743 | spin_lock(&pTcon->stat_lock); | ||
744 | pTcon->bytes_written += total_written; | ||
745 | spin_unlock(&pTcon->stat_lock); | ||
746 | } | ||
747 | #endif | ||
748 | |||
749 | /* since the write may have blocked check these pointers again */ | ||
750 | if (file->f_dentry) { | ||
751 | if (file->f_dentry->d_inode) { | ||
752 | struct inode *inode = file->f_dentry->d_inode; | ||
753 | inode->i_ctime = inode->i_mtime = | ||
754 | current_fs_time(inode->i_sb); | ||
755 | if (total_written > 0) { | ||
756 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
757 | i_size_write(file->f_dentry->d_inode, | ||
758 | *poffset); | ||
759 | } | ||
760 | mark_inode_dirty_sync(file->f_dentry->d_inode); | ||
761 | } | ||
762 | } | ||
763 | FreeXid(xid); | ||
764 | return total_written; | ||
765 | } | ||
766 | |||
767 | static ssize_t cifs_write(struct file *file, const char *write_data, | ||
768 | size_t write_size, loff_t *poffset) | ||
769 | { | ||
770 | int rc = 0; | ||
771 | unsigned int bytes_written = 0; | ||
772 | unsigned int total_written; | ||
773 | struct cifs_sb_info *cifs_sb; | ||
774 | struct cifsTconInfo *pTcon; | ||
775 | int xid, long_op; | ||
776 | struct cifsFileInfo *open_file; | ||
777 | |||
778 | if (file->f_dentry == NULL) | ||
779 | return -EBADF; | ||
780 | |||
781 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
782 | if (cifs_sb == NULL) | ||
783 | return -EBADF; | ||
784 | |||
785 | pTcon = cifs_sb->tcon; | ||
786 | |||
787 | /* cFYI(1, | ||
788 | (" write %d bytes to offset %lld of %s", write_size, | ||
789 | *poffset, file->f_dentry->d_name.name)); */ | ||
790 | |||
791 | if (file->private_data == NULL) | ||
792 | return -EBADF; | ||
793 | else | ||
794 | open_file = (struct cifsFileInfo *)file->private_data; | ||
795 | |||
796 | xid = GetXid(); | ||
797 | if (file->f_dentry->d_inode == NULL) { | ||
798 | FreeXid(xid); | ||
799 | return -EBADF; | ||
800 | } | ||
801 | |||
802 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
803 | long_op = 2; /* writes past end of file can take a long time */ | ||
804 | else | ||
805 | long_op = 1; | ||
806 | |||
807 | for (total_written = 0; write_size > total_written; | ||
808 | total_written += bytes_written) { | ||
809 | rc = -EAGAIN; | ||
810 | while (rc == -EAGAIN) { | ||
811 | if (file->private_data == NULL) { | ||
812 | /* file has been closed on us */ | ||
813 | FreeXid(xid); | ||
814 | /* if we have gotten here we have written some data | ||
815 | and blocked, and the file has been freed on us | ||
816 | while we blocked so return what we managed to | ||
817 | write */ | ||
818 | return total_written; | ||
819 | } | ||
820 | if (open_file->closePend) { | ||
821 | FreeXid(xid); | ||
822 | if (total_written) | ||
823 | return total_written; | ||
824 | else | ||
825 | return -EBADF; | ||
826 | } | ||
827 | if (open_file->invalidHandle) { | ||
828 | if ((file->f_dentry == NULL) || | ||
829 | (file->f_dentry->d_inode == NULL)) { | ||
830 | FreeXid(xid); | ||
831 | return total_written; | ||
832 | } | ||
833 | /* we could deadlock if we called | ||
834 | filemap_fdatawait from here so tell | ||
835 | reopen_file not to flush data to | ||
836 | server now */ | ||
837 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
838 | file, FALSE); | ||
839 | if (rc != 0) | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | rc = CIFSSMBWrite(xid, pTcon, | ||
844 | open_file->netfid, | ||
845 | min_t(const int, cifs_sb->wsize, | ||
846 | write_size - total_written), | ||
847 | *poffset, &bytes_written, | ||
848 | write_data + total_written, NULL, long_op); | ||
849 | } | ||
850 | if (rc || (bytes_written == 0)) { | ||
851 | if (total_written) | ||
852 | break; | ||
853 | else { | ||
854 | FreeXid(xid); | ||
855 | return rc; | ||
856 | } | ||
857 | } else | ||
858 | *poffset += bytes_written; | ||
859 | long_op = FALSE; /* subsequent writes fast - | ||
860 | 15 seconds is plenty */ | ||
861 | } | ||
862 | |||
863 | #ifdef CONFIG_CIFS_STATS | ||
864 | if (total_written > 0) { | ||
865 | atomic_inc(&pTcon->num_writes); | ||
866 | spin_lock(&pTcon->stat_lock); | ||
867 | pTcon->bytes_written += total_written; | ||
868 | spin_unlock(&pTcon->stat_lock); | ||
869 | } | ||
870 | #endif | ||
871 | |||
872 | /* since the write may have blocked check these pointers again */ | ||
873 | if (file->f_dentry) { | ||
874 | if (file->f_dentry->d_inode) { | ||
875 | file->f_dentry->d_inode->i_ctime = | ||
876 | file->f_dentry->d_inode->i_mtime = CURRENT_TIME; | ||
877 | if (total_written > 0) { | ||
878 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
879 | i_size_write(file->f_dentry->d_inode, | ||
880 | *poffset); | ||
881 | } | ||
882 | mark_inode_dirty_sync(file->f_dentry->d_inode); | ||
883 | } | ||
884 | } | ||
885 | FreeXid(xid); | ||
886 | return total_written; | ||
887 | } | ||
888 | |||
889 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | ||
890 | { | ||
891 | struct address_space *mapping = page->mapping; | ||
892 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
893 | char *write_data; | ||
894 | int rc = -EFAULT; | ||
895 | int bytes_written = 0; | ||
896 | struct cifs_sb_info *cifs_sb; | ||
897 | struct cifsTconInfo *pTcon; | ||
898 | struct inode *inode; | ||
899 | struct cifsInodeInfo *cifsInode; | ||
900 | struct cifsFileInfo *open_file = NULL; | ||
901 | struct list_head *tmp; | ||
902 | struct list_head *tmp1; | ||
903 | |||
904 | if (!mapping || !mapping->host) | ||
905 | return -EFAULT; | ||
906 | |||
907 | inode = page->mapping->host; | ||
908 | cifs_sb = CIFS_SB(inode->i_sb); | ||
909 | pTcon = cifs_sb->tcon; | ||
910 | |||
911 | offset += (loff_t)from; | ||
912 | write_data = kmap(page); | ||
913 | write_data += from; | ||
914 | |||
915 | if ((to > PAGE_CACHE_SIZE) || (from > to)) { | ||
916 | kunmap(page); | ||
917 | return -EIO; | ||
918 | } | ||
919 | |||
920 | /* racing with truncate? */ | ||
921 | if (offset > mapping->host->i_size) { | ||
922 | kunmap(page); | ||
923 | return 0; /* don't care */ | ||
924 | } | ||
925 | |||
926 | /* check to make sure that we are not extending the file */ | ||
927 | if (mapping->host->i_size - offset < (loff_t)to) | ||
928 | to = (unsigned)(mapping->host->i_size - offset); | ||
929 | |||
930 | cifsInode = CIFS_I(mapping->host); | ||
931 | read_lock(&GlobalSMBSeslock); | ||
932 | /* BB we should start at the end */ | ||
933 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | ||
934 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
935 | if (open_file->closePend) | ||
936 | continue; | ||
937 | /* We check if file is open for writing first */ | ||
938 | if ((open_file->pfile) && | ||
939 | ((open_file->pfile->f_flags & O_RDWR) || | ||
940 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
941 | read_unlock(&GlobalSMBSeslock); | ||
942 | bytes_written = cifs_write(open_file->pfile, | ||
943 | write_data, to-from, | ||
944 | &offset); | ||
945 | read_lock(&GlobalSMBSeslock); | ||
946 | /* Does mm or vfs already set times? */ | ||
947 | inode->i_atime = | ||
948 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
949 | if ((bytes_written > 0) && (offset)) { | ||
950 | rc = 0; | ||
951 | } else if (bytes_written < 0) { | ||
952 | if (rc == -EBADF) { | ||
953 | /* have seen a case in which kernel seemed to | ||
954 | have closed/freed a file even with writes | ||
955 | active so we might as well see if there are | ||
956 | other file structs to try for the same | ||
957 | inode before giving up */ | ||
958 | continue; | ||
959 | } else | ||
960 | rc = bytes_written; | ||
961 | } | ||
962 | break; /* now that we found a valid file handle and | ||
963 | tried to write to it we are done, no sense | ||
964 | continuing to loop looking for another */ | ||
965 | } | ||
966 | if (tmp->next == NULL) { | ||
967 | cFYI(1, ("File instance %p removed", tmp)); | ||
968 | break; | ||
969 | } | ||
970 | } | ||
971 | read_unlock(&GlobalSMBSeslock); | ||
972 | if (open_file == NULL) { | ||
973 | cFYI(1, ("No writeable filehandles for inode")); | ||
974 | rc = -EIO; | ||
975 | } | ||
976 | |||
977 | kunmap(page); | ||
978 | return rc; | ||
979 | } | ||
980 | |||
981 | #if 0 | ||
982 | static int cifs_writepages(struct address_space *mapping, | ||
983 | struct writeback_control *wbc) | ||
984 | { | ||
985 | int rc = -EFAULT; | ||
986 | int xid; | ||
987 | |||
988 | xid = GetXid(); | ||
989 | |||
990 | /* Find contiguous pages then iterate through repeating | ||
991 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | ||
992 | support then send larger writes via kevec so as to eliminate | ||
993 | a memcpy */ | ||
994 | FreeXid(xid); | ||
995 | return rc; | ||
996 | } | ||
997 | #endif | ||
998 | |||
999 | static int cifs_writepage(struct page* page, struct writeback_control *wbc) | ||
1000 | { | ||
1001 | int rc = -EFAULT; | ||
1002 | int xid; | ||
1003 | |||
1004 | xid = GetXid(); | ||
1005 | /* BB add check for wbc flags */ | ||
1006 | page_cache_get(page); | ||
1007 | if (!PageUptodate(page)) { | ||
1008 | cFYI(1, ("ppw - page not up to date")); | ||
1009 | } | ||
1010 | |||
1011 | rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); | ||
1012 | SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ | ||
1013 | unlock_page(page); | ||
1014 | page_cache_release(page); | ||
1015 | FreeXid(xid); | ||
1016 | return rc; | ||
1017 | } | ||
1018 | |||
1019 | static int cifs_commit_write(struct file *file, struct page *page, | ||
1020 | unsigned offset, unsigned to) | ||
1021 | { | ||
1022 | int xid; | ||
1023 | int rc = 0; | ||
1024 | struct inode *inode = page->mapping->host; | ||
1025 | loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
1026 | char *page_data; | ||
1027 | |||
1028 | xid = GetXid(); | ||
1029 | cFYI(1, ("commit write for page %p up to position %lld for %d", | ||
1030 | page, position, to)); | ||
1031 | if (position > inode->i_size) { | ||
1032 | i_size_write(inode, position); | ||
1033 | /* if (file->private_data == NULL) { | ||
1034 | rc = -EBADF; | ||
1035 | } else { | ||
1036 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1037 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1038 | rc = -EAGAIN; | ||
1039 | while (rc == -EAGAIN) { | ||
1040 | if ((open_file->invalidHandle) && | ||
1041 | (!open_file->closePend)) { | ||
1042 | rc = cifs_reopen_file( | ||
1043 | file->f_dentry->d_inode, file); | ||
1044 | if (rc != 0) | ||
1045 | break; | ||
1046 | } | ||
1047 | if (!open_file->closePend) { | ||
1048 | rc = CIFSSMBSetFileSize(xid, | ||
1049 | cifs_sb->tcon, position, | ||
1050 | open_file->netfid, | ||
1051 | open_file->pid, FALSE); | ||
1052 | } else { | ||
1053 | rc = -EBADF; | ||
1054 | break; | ||
1055 | } | ||
1056 | } | ||
1057 | cFYI(1, (" SetEOF (commit write) rc = %d", rc)); | ||
1058 | } */ | ||
1059 | } | ||
1060 | if (!PageUptodate(page)) { | ||
1061 | position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; | ||
1062 | /* can not rely on (or let) writepage write this data */ | ||
1063 | if (to < offset) { | ||
1064 | cFYI(1, ("Illegal offsets, can not copy from %d to %d", | ||
1065 | offset, to)); | ||
1066 | FreeXid(xid); | ||
1067 | return rc; | ||
1068 | } | ||
1069 | /* this is probably better than directly calling | ||
1070 | partialpage_write since in this function the file handle is | ||
1071 | known which we might as well leverage */ | ||
1072 | /* BB check if anything else missing out of ppw | ||
1073 | such as updating last write time */ | ||
1074 | page_data = kmap(page); | ||
1075 | rc = cifs_write(file, page_data + offset, to-offset, | ||
1076 | &position); | ||
1077 | if (rc > 0) | ||
1078 | rc = 0; | ||
1079 | /* else if (rc < 0) should we set writebehind rc? */ | ||
1080 | kunmap(page); | ||
1081 | } else { | ||
1082 | set_page_dirty(page); | ||
1083 | } | ||
1084 | |||
1085 | FreeXid(xid); | ||
1086 | return rc; | ||
1087 | } | ||
1088 | |||
1089 | int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
1090 | { | ||
1091 | int xid; | ||
1092 | int rc = 0; | ||
1093 | struct inode *inode = file->f_dentry->d_inode; | ||
1094 | |||
1095 | xid = GetXid(); | ||
1096 | |||
1097 | cFYI(1, ("Sync file - name: %s datasync: 0x%x ", | ||
1098 | dentry->d_name.name, datasync)); | ||
1099 | |||
1100 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1101 | if (rc == 0) | ||
1102 | CIFS_I(inode)->write_behind_rc = 0; | ||
1103 | FreeXid(xid); | ||
1104 | return rc; | ||
1105 | } | ||
1106 | |||
1107 | /* static int cifs_sync_page(struct page *page) | ||
1108 | { | ||
1109 | struct address_space *mapping; | ||
1110 | struct inode *inode; | ||
1111 | unsigned long index = page->index; | ||
1112 | unsigned int rpages = 0; | ||
1113 | int rc = 0; | ||
1114 | |||
1115 | cFYI(1, ("sync page %p",page)); | ||
1116 | mapping = page->mapping; | ||
1117 | if (!mapping) | ||
1118 | return 0; | ||
1119 | inode = mapping->host; | ||
1120 | if (!inode) | ||
1121 | return 0; */ | ||
1122 | |||
1123 | /* fill in rpages then | ||
1124 | result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ | ||
1125 | |||
1126 | /* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); | ||
1127 | |||
1128 | if (rc < 0) | ||
1129 | return rc; | ||
1130 | return 0; | ||
1131 | } */ | ||
1132 | |||
1133 | /* | ||
1134 | * As file closes, flush all cached write data for this inode checking | ||
1135 | * for write behind errors. | ||
1136 | */ | ||
1137 | int cifs_flush(struct file *file) | ||
1138 | { | ||
1139 | struct inode * inode = file->f_dentry->d_inode; | ||
1140 | int rc = 0; | ||
1141 | |||
1142 | /* Rather than do the steps manually: | ||
1143 | lock the inode for writing | ||
1144 | loop through pages looking for write behind data (dirty pages) | ||
1145 | coalesce into contiguous 16K (or smaller) chunks to write to server | ||
1146 | send to server (prefer in parallel) | ||
1147 | deal with writebehind errors | ||
1148 | unlock inode for writing | ||
1149 | filemapfdatawrite appears easier for the time being */ | ||
1150 | |||
1151 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1152 | if (!rc) /* reset wb rc if we were able to write out dirty pages */ | ||
1153 | CIFS_I(inode)->write_behind_rc = 0; | ||
1154 | |||
1155 | cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc)); | ||
1156 | |||
1157 | return rc; | ||
1158 | } | ||
1159 | |||
1160 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | ||
1161 | size_t read_size, loff_t *poffset) | ||
1162 | { | ||
1163 | int rc = -EACCES; | ||
1164 | unsigned int bytes_read = 0; | ||
1165 | unsigned int total_read = 0; | ||
1166 | unsigned int current_read_size; | ||
1167 | struct cifs_sb_info *cifs_sb; | ||
1168 | struct cifsTconInfo *pTcon; | ||
1169 | int xid; | ||
1170 | struct cifsFileInfo *open_file; | ||
1171 | char *smb_read_data; | ||
1172 | char __user *current_offset; | ||
1173 | struct smb_com_read_rsp *pSMBr; | ||
1174 | |||
1175 | xid = GetXid(); | ||
1176 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1177 | pTcon = cifs_sb->tcon; | ||
1178 | |||
1179 | if (file->private_data == NULL) { | ||
1180 | FreeXid(xid); | ||
1181 | return -EBADF; | ||
1182 | } | ||
1183 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1184 | |||
1185 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
1186 | cFYI(1, ("attempting read on write only file instance")); | ||
1187 | } | ||
1188 | for (total_read = 0, current_offset = read_data; | ||
1189 | read_size > total_read; | ||
1190 | total_read += bytes_read, current_offset += bytes_read) { | ||
1191 | current_read_size = min_t(const int, read_size - total_read, | ||
1192 | cifs_sb->rsize); | ||
1193 | rc = -EAGAIN; | ||
1194 | smb_read_data = NULL; | ||
1195 | while (rc == -EAGAIN) { | ||
1196 | if ((open_file->invalidHandle) && | ||
1197 | (!open_file->closePend)) { | ||
1198 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1199 | file, TRUE); | ||
1200 | if (rc != 0) | ||
1201 | break; | ||
1202 | } | ||
1203 | |||
1204 | rc = CIFSSMBRead(xid, pTcon, | ||
1205 | open_file->netfid, | ||
1206 | current_read_size, *poffset, | ||
1207 | &bytes_read, &smb_read_data); | ||
1208 | |||
1209 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | ||
1210 | if (copy_to_user(current_offset, | ||
1211 | smb_read_data + 4 /* RFC1001 hdr */ | ||
1212 | + le16_to_cpu(pSMBr->DataOffset), | ||
1213 | bytes_read)) { | ||
1214 | rc = -EFAULT; | ||
1215 | FreeXid(xid); | ||
1216 | return rc; | ||
1217 | } | ||
1218 | if (smb_read_data) { | ||
1219 | cifs_buf_release(smb_read_data); | ||
1220 | smb_read_data = NULL; | ||
1221 | } | ||
1222 | } | ||
1223 | if (rc || (bytes_read == 0)) { | ||
1224 | if (total_read) { | ||
1225 | break; | ||
1226 | } else { | ||
1227 | FreeXid(xid); | ||
1228 | return rc; | ||
1229 | } | ||
1230 | } else { | ||
1231 | #ifdef CONFIG_CIFS_STATS | ||
1232 | atomic_inc(&pTcon->num_reads); | ||
1233 | spin_lock(&pTcon->stat_lock); | ||
1234 | pTcon->bytes_read += total_read; | ||
1235 | spin_unlock(&pTcon->stat_lock); | ||
1236 | #endif | ||
1237 | *poffset += bytes_read; | ||
1238 | } | ||
1239 | } | ||
1240 | FreeXid(xid); | ||
1241 | return total_read; | ||
1242 | } | ||
1243 | |||
1244 | |||
1245 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | ||
1246 | loff_t *poffset) | ||
1247 | { | ||
1248 | int rc = -EACCES; | ||
1249 | unsigned int bytes_read = 0; | ||
1250 | unsigned int total_read; | ||
1251 | unsigned int current_read_size; | ||
1252 | struct cifs_sb_info *cifs_sb; | ||
1253 | struct cifsTconInfo *pTcon; | ||
1254 | int xid; | ||
1255 | char *current_offset; | ||
1256 | struct cifsFileInfo *open_file; | ||
1257 | |||
1258 | xid = GetXid(); | ||
1259 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1260 | pTcon = cifs_sb->tcon; | ||
1261 | |||
1262 | if (file->private_data == NULL) { | ||
1263 | FreeXid(xid); | ||
1264 | return -EBADF; | ||
1265 | } | ||
1266 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1267 | |||
1268 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | ||
1269 | cFYI(1, ("attempting read on write only file instance")); | ||
1270 | |||
1271 | for (total_read = 0, current_offset = read_data; | ||
1272 | read_size > total_read; | ||
1273 | total_read += bytes_read, current_offset += bytes_read) { | ||
1274 | current_read_size = min_t(const int, read_size - total_read, | ||
1275 | cifs_sb->rsize); | ||
1276 | rc = -EAGAIN; | ||
1277 | while (rc == -EAGAIN) { | ||
1278 | if ((open_file->invalidHandle) && | ||
1279 | (!open_file->closePend)) { | ||
1280 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1281 | file, TRUE); | ||
1282 | if (rc != 0) | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | rc = CIFSSMBRead(xid, pTcon, | ||
1287 | open_file->netfid, | ||
1288 | current_read_size, *poffset, | ||
1289 | &bytes_read, ¤t_offset); | ||
1290 | } | ||
1291 | if (rc || (bytes_read == 0)) { | ||
1292 | if (total_read) { | ||
1293 | break; | ||
1294 | } else { | ||
1295 | FreeXid(xid); | ||
1296 | return rc; | ||
1297 | } | ||
1298 | } else { | ||
1299 | #ifdef CONFIG_CIFS_STATS | ||
1300 | atomic_inc(&pTcon->num_reads); | ||
1301 | spin_lock(&pTcon->stat_lock); | ||
1302 | pTcon->bytes_read += total_read; | ||
1303 | spin_unlock(&pTcon->stat_lock); | ||
1304 | #endif | ||
1305 | *poffset += bytes_read; | ||
1306 | } | ||
1307 | } | ||
1308 | FreeXid(xid); | ||
1309 | return total_read; | ||
1310 | } | ||
1311 | |||
1312 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | ||
1313 | { | ||
1314 | struct dentry *dentry = file->f_dentry; | ||
1315 | int rc, xid; | ||
1316 | |||
1317 | xid = GetXid(); | ||
1318 | rc = cifs_revalidate(dentry); | ||
1319 | if (rc) { | ||
1320 | cFYI(1, ("Validation prior to mmap failed, error=%d", rc)); | ||
1321 | FreeXid(xid); | ||
1322 | return rc; | ||
1323 | } | ||
1324 | rc = generic_file_mmap(file, vma); | ||
1325 | FreeXid(xid); | ||
1326 | return rc; | ||
1327 | } | ||
1328 | |||
1329 | |||
1330 | static void cifs_copy_cache_pages(struct address_space *mapping, | ||
1331 | struct list_head *pages, int bytes_read, char *data, | ||
1332 | struct pagevec *plru_pvec) | ||
1333 | { | ||
1334 | struct page *page; | ||
1335 | char *target; | ||
1336 | |||
1337 | while (bytes_read > 0) { | ||
1338 | if (list_empty(pages)) | ||
1339 | break; | ||
1340 | |||
1341 | page = list_entry(pages->prev, struct page, lru); | ||
1342 | list_del(&page->lru); | ||
1343 | |||
1344 | if (add_to_page_cache(page, mapping, page->index, | ||
1345 | GFP_KERNEL)) { | ||
1346 | page_cache_release(page); | ||
1347 | cFYI(1, ("Add page cache failed")); | ||
1348 | continue; | ||
1349 | } | ||
1350 | |||
1351 | target = kmap_atomic(page,KM_USER0); | ||
1352 | |||
1353 | if (PAGE_CACHE_SIZE > bytes_read) { | ||
1354 | memcpy(target, data, bytes_read); | ||
1355 | /* zero the tail end of this partial page */ | ||
1356 | memset(target + bytes_read, 0, | ||
1357 | PAGE_CACHE_SIZE - bytes_read); | ||
1358 | bytes_read = 0; | ||
1359 | } else { | ||
1360 | memcpy(target, data, PAGE_CACHE_SIZE); | ||
1361 | bytes_read -= PAGE_CACHE_SIZE; | ||
1362 | } | ||
1363 | kunmap_atomic(target, KM_USER0); | ||
1364 | |||
1365 | flush_dcache_page(page); | ||
1366 | SetPageUptodate(page); | ||
1367 | unlock_page(page); | ||
1368 | if (!pagevec_add(plru_pvec, page)) | ||
1369 | __pagevec_lru_add(plru_pvec); | ||
1370 | data += PAGE_CACHE_SIZE; | ||
1371 | } | ||
1372 | return; | ||
1373 | } | ||
1374 | |||
1375 | static int cifs_readpages(struct file *file, struct address_space *mapping, | ||
1376 | struct list_head *page_list, unsigned num_pages) | ||
1377 | { | ||
1378 | int rc = -EACCES; | ||
1379 | int xid; | ||
1380 | loff_t offset; | ||
1381 | struct page *page; | ||
1382 | struct cifs_sb_info *cifs_sb; | ||
1383 | struct cifsTconInfo *pTcon; | ||
1384 | int bytes_read = 0; | ||
1385 | unsigned int read_size,i; | ||
1386 | char *smb_read_data = NULL; | ||
1387 | struct smb_com_read_rsp *pSMBr; | ||
1388 | struct pagevec lru_pvec; | ||
1389 | struct cifsFileInfo *open_file; | ||
1390 | |||
1391 | xid = GetXid(); | ||
1392 | if (file->private_data == NULL) { | ||
1393 | FreeXid(xid); | ||
1394 | return -EBADF; | ||
1395 | } | ||
1396 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1397 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1398 | pTcon = cifs_sb->tcon; | ||
1399 | |||
1400 | pagevec_init(&lru_pvec, 0); | ||
1401 | |||
1402 | for (i = 0; i < num_pages; ) { | ||
1403 | unsigned contig_pages; | ||
1404 | struct page *tmp_page; | ||
1405 | unsigned long expected_index; | ||
1406 | |||
1407 | if (list_empty(page_list)) | ||
1408 | break; | ||
1409 | |||
1410 | page = list_entry(page_list->prev, struct page, lru); | ||
1411 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1412 | |||
1413 | /* count adjacent pages that we will read into */ | ||
1414 | contig_pages = 0; | ||
1415 | expected_index = | ||
1416 | list_entry(page_list->prev, struct page, lru)->index; | ||
1417 | list_for_each_entry_reverse(tmp_page,page_list,lru) { | ||
1418 | if (tmp_page->index == expected_index) { | ||
1419 | contig_pages++; | ||
1420 | expected_index++; | ||
1421 | } else | ||
1422 | break; | ||
1423 | } | ||
1424 | if (contig_pages + i > num_pages) | ||
1425 | contig_pages = num_pages - i; | ||
1426 | |||
1427 | /* for reads over a certain size could initiate async | ||
1428 | read ahead */ | ||
1429 | |||
1430 | read_size = contig_pages * PAGE_CACHE_SIZE; | ||
1431 | /* Read size needs to be in multiples of one page */ | ||
1432 | read_size = min_t(const unsigned int, read_size, | ||
1433 | cifs_sb->rsize & PAGE_CACHE_MASK); | ||
1434 | |||
1435 | rc = -EAGAIN; | ||
1436 | while (rc == -EAGAIN) { | ||
1437 | if ((open_file->invalidHandle) && | ||
1438 | (!open_file->closePend)) { | ||
1439 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1440 | file, TRUE); | ||
1441 | if (rc != 0) | ||
1442 | break; | ||
1443 | } | ||
1444 | |||
1445 | rc = CIFSSMBRead(xid, pTcon, | ||
1446 | open_file->netfid, | ||
1447 | read_size, offset, | ||
1448 | &bytes_read, &smb_read_data); | ||
1449 | /* BB need to check return code here */ | ||
1450 | if (rc== -EAGAIN) { | ||
1451 | if (smb_read_data) { | ||
1452 | cifs_buf_release(smb_read_data); | ||
1453 | smb_read_data = NULL; | ||
1454 | } | ||
1455 | } | ||
1456 | } | ||
1457 | if ((rc < 0) || (smb_read_data == NULL)) { | ||
1458 | cFYI(1, ("Read error in readpages: %d", rc)); | ||
1459 | /* clean up remaing pages off list */ | ||
1460 | while (!list_empty(page_list) && (i < num_pages)) { | ||
1461 | page = list_entry(page_list->prev, struct page, | ||
1462 | lru); | ||
1463 | list_del(&page->lru); | ||
1464 | page_cache_release(page); | ||
1465 | } | ||
1466 | break; | ||
1467 | } else if (bytes_read > 0) { | ||
1468 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | ||
1469 | cifs_copy_cache_pages(mapping, page_list, bytes_read, | ||
1470 | smb_read_data + 4 /* RFC1001 hdr */ + | ||
1471 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | ||
1472 | |||
1473 | i += bytes_read >> PAGE_CACHE_SHIFT; | ||
1474 | #ifdef CONFIG_CIFS_STATS | ||
1475 | atomic_inc(&pTcon->num_reads); | ||
1476 | spin_lock(&pTcon->stat_lock); | ||
1477 | pTcon->bytes_read += bytes_read; | ||
1478 | spin_unlock(&pTcon->stat_lock); | ||
1479 | #endif | ||
1480 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | ||
1481 | i++; /* account for partial page */ | ||
1482 | |||
1483 | /* server copy of file can have smaller size | ||
1484 | than client */ | ||
1485 | /* BB do we need to verify this common case ? | ||
1486 | this case is ok - if we are at server EOF | ||
1487 | we will hit it on next read */ | ||
1488 | |||
1489 | /* while (!list_empty(page_list) && (i < num_pages)) { | ||
1490 | page = list_entry(page_list->prev, | ||
1491 | struct page, list); | ||
1492 | list_del(&page->list); | ||
1493 | page_cache_release(page); | ||
1494 | } | ||
1495 | break; */ | ||
1496 | } | ||
1497 | } else { | ||
1498 | cFYI(1, ("No bytes read (%d) at offset %lld . " | ||
1499 | "Cleaning remaining pages from readahead list", | ||
1500 | bytes_read, offset)); | ||
1501 | /* BB turn off caching and do new lookup on | ||
1502 | file size at server? */ | ||
1503 | while (!list_empty(page_list) && (i < num_pages)) { | ||
1504 | page = list_entry(page_list->prev, struct page, | ||
1505 | lru); | ||
1506 | list_del(&page->lru); | ||
1507 | |||
1508 | /* BB removeme - replace with zero of page? */ | ||
1509 | page_cache_release(page); | ||
1510 | } | ||
1511 | break; | ||
1512 | } | ||
1513 | if (smb_read_data) { | ||
1514 | cifs_buf_release(smb_read_data); | ||
1515 | smb_read_data = NULL; | ||
1516 | } | ||
1517 | bytes_read = 0; | ||
1518 | } | ||
1519 | |||
1520 | pagevec_lru_add(&lru_pvec); | ||
1521 | |||
1522 | /* need to free smb_read_data buf before exit */ | ||
1523 | if (smb_read_data) { | ||
1524 | cifs_buf_release(smb_read_data); | ||
1525 | smb_read_data = NULL; | ||
1526 | } | ||
1527 | |||
1528 | FreeXid(xid); | ||
1529 | return rc; | ||
1530 | } | ||
1531 | |||
1532 | static int cifs_readpage_worker(struct file *file, struct page *page, | ||
1533 | loff_t *poffset) | ||
1534 | { | ||
1535 | char *read_data; | ||
1536 | int rc; | ||
1537 | |||
1538 | page_cache_get(page); | ||
1539 | read_data = kmap(page); | ||
1540 | /* for reads over a certain size could initiate async read ahead */ | ||
1541 | |||
1542 | rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); | ||
1543 | |||
1544 | if (rc < 0) | ||
1545 | goto io_error; | ||
1546 | else | ||
1547 | cFYI(1, ("Bytes read %d ",rc)); | ||
1548 | |||
1549 | file->f_dentry->d_inode->i_atime = | ||
1550 | current_fs_time(file->f_dentry->d_inode->i_sb); | ||
1551 | |||
1552 | if (PAGE_CACHE_SIZE > rc) | ||
1553 | memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); | ||
1554 | |||
1555 | flush_dcache_page(page); | ||
1556 | SetPageUptodate(page); | ||
1557 | rc = 0; | ||
1558 | |||
1559 | io_error: | ||
1560 | kunmap(page); | ||
1561 | page_cache_release(page); | ||
1562 | return rc; | ||
1563 | } | ||
1564 | |||
1565 | static int cifs_readpage(struct file *file, struct page *page) | ||
1566 | { | ||
1567 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1568 | int rc = -EACCES; | ||
1569 | int xid; | ||
1570 | |||
1571 | xid = GetXid(); | ||
1572 | |||
1573 | if (file->private_data == NULL) { | ||
1574 | FreeXid(xid); | ||
1575 | return -EBADF; | ||
1576 | } | ||
1577 | |||
1578 | cFYI(1, ("readpage %p at offset %d 0x%x\n", | ||
1579 | page, (int)offset, (int)offset)); | ||
1580 | |||
1581 | rc = cifs_readpage_worker(file, page, &offset); | ||
1582 | |||
1583 | unlock_page(page); | ||
1584 | |||
1585 | FreeXid(xid); | ||
1586 | return rc; | ||
1587 | } | ||
1588 | |||
1589 | /* We do not want to update the file size from server for inodes | ||
1590 | open for write - to avoid races with writepage extending | ||
1591 | the file - in the future we could consider allowing | ||
1592 | refreshing the inode only on increases in the file size | ||
1593 | but this is tricky to do without racing with writebehind | ||
1594 | page caching in the current Linux kernel design */ | ||
1595 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | ||
1596 | { | ||
1597 | struct list_head *tmp; | ||
1598 | struct list_head *tmp1; | ||
1599 | struct cifsFileInfo *open_file = NULL; | ||
1600 | int rc = TRUE; | ||
1601 | |||
1602 | if (cifsInode == NULL) | ||
1603 | return rc; | ||
1604 | |||
1605 | read_lock(&GlobalSMBSeslock); | ||
1606 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | ||
1607 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
1608 | if (open_file == NULL) | ||
1609 | break; | ||
1610 | if (open_file->closePend) | ||
1611 | continue; | ||
1612 | /* We check if file is open for writing, | ||
1613 | BB we could supplement this with a check to see if file size | ||
1614 | changes have been flushed to server - ie inode metadata dirty */ | ||
1615 | if ((open_file->pfile) && | ||
1616 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1617 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1618 | rc = FALSE; | ||
1619 | break; | ||
1620 | } | ||
1621 | if (tmp->next == NULL) { | ||
1622 | cFYI(1, ("File instance %p removed", tmp)); | ||
1623 | break; | ||
1624 | } | ||
1625 | } | ||
1626 | read_unlock(&GlobalSMBSeslock); | ||
1627 | return rc; | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | static int cifs_prepare_write(struct file *file, struct page *page, | ||
1632 | unsigned from, unsigned to) | ||
1633 | { | ||
1634 | int rc = 0; | ||
1635 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1636 | cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); | ||
1637 | if (!PageUptodate(page)) { | ||
1638 | /* if (to - from != PAGE_CACHE_SIZE) { | ||
1639 | void *kaddr = kmap_atomic(page, KM_USER0); | ||
1640 | memset(kaddr, 0, from); | ||
1641 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); | ||
1642 | flush_dcache_page(page); | ||
1643 | kunmap_atomic(kaddr, KM_USER0); | ||
1644 | } */ | ||
1645 | /* If we are writing a full page it will be up to date, | ||
1646 | no need to read from the server */ | ||
1647 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) | ||
1648 | SetPageUptodate(page); | ||
1649 | |||
1650 | /* might as well read a page, it is fast enough */ | ||
1651 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | ||
1652 | rc = cifs_readpage_worker(file, page, &offset); | ||
1653 | } else { | ||
1654 | /* should we try using another file handle if there is one - | ||
1655 | how would we lock it to prevent close of that handle | ||
1656 | racing with this read? | ||
1657 | In any case this will be written out by commit_write */ | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | /* BB should we pass any errors back? | ||
1662 | e.g. if we do not have read access to the file */ | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | struct address_space_operations cifs_addr_ops = { | ||
1667 | .readpage = cifs_readpage, | ||
1668 | .readpages = cifs_readpages, | ||
1669 | .writepage = cifs_writepage, | ||
1670 | .prepare_write = cifs_prepare_write, | ||
1671 | .commit_write = cifs_commit_write, | ||
1672 | .set_page_dirty = __set_page_dirty_nobuffers, | ||
1673 | /* .sync_page = cifs_sync_page, */ | ||
1674 | /* .direct_IO = */ | ||
1675 | }; | ||