blob: 7ef30efe8f98de8a86466af17476f8c0de23a542 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Steve French37c0eb42005-10-05 14:50:29 -070024#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/stat.h>
26#include <linux/fcntl.h>
Steve French37c0eb42005-10-05 14:50:29 -070027#include <linux/mpage.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/pagemap.h>
29#include <linux/pagevec.h>
30#include <linux/smp_lock.h>
Steve French37c0eb42005-10-05 14:50:29 -070031#include <linux/writeback.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/div64.h>
34#include "cifsfs.h"
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41
42static inline struct cifsFileInfo *cifs_init_private(
43 struct cifsFileInfo *private_data, struct inode *inode,
44 struct file *file, __u16 netfid)
45{
46 memset(private_data, 0, sizeof(struct cifsFileInfo));
47 private_data->netfid = netfid;
48 private_data->pid = current->tgid;
49 init_MUTEX(&private_data->fh_sem);
50 private_data->pfile = file; /* needed for writepage */
51 private_data->pInode = inode;
52 private_data->invalidHandle = FALSE;
53 private_data->closePend = FALSE;
Steve French23e7dd72005-10-20 13:44:56 -070054 /* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 return private_data;
61}
62
63static inline int cifs_convert_flags(unsigned int flags)
64{
65 if ((flags & O_ACCMODE) == O_RDONLY)
66 return GENERIC_READ;
67 else if ((flags & O_ACCMODE) == O_WRONLY)
68 return GENERIC_WRITE;
69 else if ((flags & O_ACCMODE) == O_RDWR) {
70 /* GENERIC_ALL is too much permission to request
71 can cause unnecessary access denied on create */
72 /* return GENERIC_ALL; */
73 return (GENERIC_READ | GENERIC_WRITE);
74 }
75
76 return 0x20197;
77}
78
79static inline int cifs_get_disposition(unsigned int flags)
80{
81 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
82 return FILE_CREATE;
83 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
84 return FILE_OVERWRITE_IF;
85 else if ((flags & O_CREAT) == O_CREAT)
86 return FILE_OPEN_IF;
87 else
88 return FILE_OPEN;
89}
90
91/* all arguments to this function must be checked for validity in caller */
92static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
93 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
94 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
95 char *full_path, int xid)
96{
97 struct timespec temp;
98 int rc;
99
100 /* want handles we can use to read with first
101 in the list so we do not have to walk the
102 list to search for one in prepare_write */
103 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
104 list_add_tail(&pCifsFile->flist,
105 &pCifsInode->openFileList);
106 } else {
107 list_add(&pCifsFile->flist,
108 &pCifsInode->openFileList);
109 }
110 write_unlock(&GlobalSMBSeslock);
111 write_unlock(&file->f_owner.lock);
112 if (pCifsInode->clientCanCacheRead) {
113 /* we have the inode open somewhere else
114 no need to discard cache data */
115 goto client_can_cache;
116 }
117
118 /* BB need same check in cifs_create too? */
119 /* if not oplocked, invalidate inode pages if mtime or file
120 size changed */
121 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
122 if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
123 (file->f_dentry->d_inode->i_size ==
124 (loff_t)le64_to_cpu(buf->EndOfFile))) {
125 cFYI(1, ("inode unchanged on server"));
126 } else {
127 if (file->f_dentry->d_inode->i_mapping) {
128 /* BB no need to lock inode until after invalidate
129 since namei code should already have it locked? */
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800130 filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 }
132 cFYI(1, ("invalidating remote inode since open detected it "
133 "changed"));
134 invalidate_remote_inode(file->f_dentry->d_inode);
135 }
136
137client_can_cache:
138 if (pTcon->ses->capabilities & CAP_UNIX)
139 rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
140 full_path, inode->i_sb, xid);
141 else
142 rc = cifs_get_inode_info(&file->f_dentry->d_inode,
143 full_path, buf, inode->i_sb, xid);
144
145 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
146 pCifsInode->clientCanCacheAll = TRUE;
147 pCifsInode->clientCanCacheRead = TRUE;
148 cFYI(1, ("Exclusive Oplock granted on inode %p",
149 file->f_dentry->d_inode));
150 } else if ((*oplock & 0xF) == OPLOCK_READ)
151 pCifsInode->clientCanCacheRead = TRUE;
152
153 return rc;
154}
155
156int cifs_open(struct inode *inode, struct file *file)
157{
158 int rc = -EACCES;
159 int xid, oplock;
160 struct cifs_sb_info *cifs_sb;
161 struct cifsTconInfo *pTcon;
162 struct cifsFileInfo *pCifsFile;
163 struct cifsInodeInfo *pCifsInode;
164 struct list_head *tmp;
165 char *full_path = NULL;
166 int desiredAccess;
167 int disposition;
168 __u16 netfid;
169 FILE_ALL_INFO *buf = NULL;
170
171 xid = GetXid();
172
173 cifs_sb = CIFS_SB(inode->i_sb);
174 pTcon = cifs_sb->tcon;
175
176 if (file->f_flags & O_CREAT) {
177 /* search inode for this file and fill in file->private_data */
178 pCifsInode = CIFS_I(file->f_dentry->d_inode);
179 read_lock(&GlobalSMBSeslock);
180 list_for_each(tmp, &pCifsInode->openFileList) {
181 pCifsFile = list_entry(tmp, struct cifsFileInfo,
182 flist);
183 if ((pCifsFile->pfile == NULL) &&
184 (pCifsFile->pid == current->tgid)) {
185 /* mode set in cifs_create */
186
187 /* needed for writepage */
188 pCifsFile->pfile = file;
189
190 file->private_data = pCifsFile;
191 break;
192 }
193 }
194 read_unlock(&GlobalSMBSeslock);
195 if (file->private_data != NULL) {
196 rc = 0;
197 FreeXid(xid);
198 return rc;
199 } else {
200 if (file->f_flags & O_EXCL)
201 cERROR(1, ("could not find file instance for "
202 "new file %p ", file));
203 }
204 }
205
Steve French7f573562005-08-30 11:32:14 -0700206 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (full_path == NULL) {
208 FreeXid(xid);
209 return -ENOMEM;
210 }
211
212 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
213 inode, file->f_flags, full_path));
214 desiredAccess = cifs_convert_flags(file->f_flags);
215
216/*********************************************************************
217 * open flag mapping table:
218 *
219 * POSIX Flag CIFS Disposition
220 * ---------- ----------------
221 * O_CREAT FILE_OPEN_IF
222 * O_CREAT | O_EXCL FILE_CREATE
223 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
224 * O_TRUNC FILE_OVERWRITE
225 * none of the above FILE_OPEN
226 *
227 * Note that there is not a direct match between disposition
228 * FILE_SUPERSEDE (ie create whether or not file exists although
229 * O_CREAT | O_TRUNC is similar but truncates the existing
230 * file rather than creating a new file as FILE_SUPERSEDE does
231 * (which uses the attributes / metadata passed in on open call)
232 *?
233 *? O_SYNC is a reasonable match to CIFS writethrough flag
234 *? and the read write flags match reasonably. O_LARGEFILE
235 *? is irrelevant because largefile support is always used
236 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
237 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
238 *********************************************************************/
239
240 disposition = cifs_get_disposition(file->f_flags);
241
242 if (oplockEnabled)
243 oplock = REQ_OPLOCK;
244 else
245 oplock = FALSE;
246
247 /* BB pass O_SYNC flag through on file attributes .. BB */
248
249 /* Also refresh inode by passing in file_info buf returned by SMBOpen
250 and calling get_inode_info with returned buf (at least helps
251 non-Unix server case) */
252
253 /* BB we can not do this if this is the second open of a file
254 and the first handle has writebehind data, we might be
255 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
256 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
257 if (!buf) {
258 rc = -ENOMEM;
259 goto out;
260 }
261 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
262 CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700263 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
264 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frencha9d02ad2005-08-24 23:06:05 -0700265 if (rc == -EIO) {
266 /* Old server, try legacy style OpenX */
267 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
268 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
269 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
270 & CIFS_MOUNT_MAP_SPECIAL_CHR);
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 if (rc) {
273 cFYI(1, ("cifs_open returned 0x%x ", rc));
274 goto out;
275 }
276 file->private_data =
277 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
278 if (file->private_data == NULL) {
279 rc = -ENOMEM;
280 goto out;
281 }
282 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
283 write_lock(&file->f_owner.lock);
284 write_lock(&GlobalSMBSeslock);
285 list_add(&pCifsFile->tlist, &pTcon->openFileList);
286
287 pCifsInode = CIFS_I(file->f_dentry->d_inode);
288 if (pCifsInode) {
289 rc = cifs_open_inode_helper(inode, file, pCifsInode,
290 pCifsFile, pTcon,
291 &oplock, buf, full_path, xid);
292 } else {
293 write_unlock(&GlobalSMBSeslock);
294 write_unlock(&file->f_owner.lock);
295 }
296
297 if (oplock & CIFS_CREATE_ACTION) {
298 /* time to set mode which we can not set earlier due to
299 problems creating new read-only files */
300 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
301 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
302 inode->i_mode,
303 (__u64)-1, (__u64)-1, 0 /* dev */,
Steve French737b7582005-04-28 22:41:06 -0700304 cifs_sb->local_nls,
305 cifs_sb->mnt_cifs_flags &
306 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 } else {
308 /* BB implement via Windows security descriptors eg
309 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
310 -1, -1, local_nls);
311 in the meantime could set r/o dos attribute when
312 perms are eg: mode & 0222 == 0 */
313 }
314 }
315
316out:
317 kfree(buf);
318 kfree(full_path);
319 FreeXid(xid);
320 return rc;
321}
322
323/* Try to reaquire byte range locks that were released when session */
324/* to server was lost */
325static int cifs_relock_file(struct cifsFileInfo *cifsFile)
326{
327 int rc = 0;
328
329/* BB list all locks open on this file and relock */
330
331 return rc;
332}
333
334static int cifs_reopen_file(struct inode *inode, struct file *file,
335 int can_flush)
336{
337 int rc = -EACCES;
338 int xid, oplock;
339 struct cifs_sb_info *cifs_sb;
340 struct cifsTconInfo *pTcon;
341 struct cifsFileInfo *pCifsFile;
342 struct cifsInodeInfo *pCifsInode;
343 char *full_path = NULL;
344 int desiredAccess;
345 int disposition = FILE_OPEN;
346 __u16 netfid;
347
348 if (inode == NULL)
349 return -EBADF;
350 if (file->private_data) {
351 pCifsFile = (struct cifsFileInfo *)file->private_data;
352 } else
353 return -EBADF;
354
355 xid = GetXid();
356 down(&pCifsFile->fh_sem);
357 if (pCifsFile->invalidHandle == FALSE) {
358 up(&pCifsFile->fh_sem);
359 FreeXid(xid);
360 return 0;
361 }
362
363 if (file->f_dentry == NULL) {
364 up(&pCifsFile->fh_sem);
365 cFYI(1, ("failed file reopen, no valid name if dentry freed"));
366 FreeXid(xid);
367 return -EBADF;
368 }
369 cifs_sb = CIFS_SB(inode->i_sb);
370 pTcon = cifs_sb->tcon;
371/* can not grab rename sem here because various ops, including
372 those that already have the rename sem can end up causing writepage
373 to get called and if the server was down that means we end up here,
374 and we can never tell if the caller already has the rename_sem */
Steve French7f573562005-08-30 11:32:14 -0700375 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (full_path == NULL) {
377 up(&pCifsFile->fh_sem);
378 FreeXid(xid);
379 return -ENOMEM;
380 }
381
382 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
383 inode, file->f_flags,full_path));
384 desiredAccess = cifs_convert_flags(file->f_flags);
385
386 if (oplockEnabled)
387 oplock = REQ_OPLOCK;
388 else
389 oplock = FALSE;
390
391 /* Can not refresh inode by passing in file_info buf to be returned
392 by SMBOpen and then calling get_inode_info with returned buf
393 since file might have write behind data that needs to be flushed
394 and server version of file size can be stale. If we knew for sure
395 that inode was not dirty locally we could do this */
396
397/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
398 if (buf == 0) {
399 up(&pCifsFile->fh_sem);
400 kfree(full_path);
401 FreeXid(xid);
402 return -ENOMEM;
403 } */
404 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
405 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700406 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
407 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 if (rc) {
409 up(&pCifsFile->fh_sem);
410 cFYI(1, ("cifs_open returned 0x%x ", rc));
411 cFYI(1, ("oplock: %d ", oplock));
412 } else {
413 pCifsFile->netfid = netfid;
414 pCifsFile->invalidHandle = FALSE;
415 up(&pCifsFile->fh_sem);
416 pCifsInode = CIFS_I(inode);
417 if (pCifsInode) {
418 if (can_flush) {
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800419 filemap_write_and_wait(inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 /* temporarily disable caching while we
421 go to server to get inode info */
422 pCifsInode->clientCanCacheAll = FALSE;
423 pCifsInode->clientCanCacheRead = FALSE;
424 if (pTcon->ses->capabilities & CAP_UNIX)
425 rc = cifs_get_inode_info_unix(&inode,
426 full_path, inode->i_sb, xid);
427 else
428 rc = cifs_get_inode_info(&inode,
429 full_path, NULL, inode->i_sb,
430 xid);
431 } /* else we are writing out data to server already
432 and could deadlock if we tried to flush data, and
433 since we do not know if we have data that would
434 invalidate the current end of file on the server
435 we can not go to the server to get the new inod
436 info */
437 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
438 pCifsInode->clientCanCacheAll = TRUE;
439 pCifsInode->clientCanCacheRead = TRUE;
440 cFYI(1, ("Exclusive Oplock granted on inode %p",
441 file->f_dentry->d_inode));
442 } else if ((oplock & 0xF) == OPLOCK_READ) {
443 pCifsInode->clientCanCacheRead = TRUE;
444 pCifsInode->clientCanCacheAll = FALSE;
445 } else {
446 pCifsInode->clientCanCacheRead = FALSE;
447 pCifsInode->clientCanCacheAll = FALSE;
448 }
449 cifs_relock_file(pCifsFile);
450 }
451 }
452
453 kfree(full_path);
454 FreeXid(xid);
455 return rc;
456}
457
458int cifs_close(struct inode *inode, struct file *file)
459{
460 int rc = 0;
461 int xid;
462 struct cifs_sb_info *cifs_sb;
463 struct cifsTconInfo *pTcon;
464 struct cifsFileInfo *pSMBFile =
465 (struct cifsFileInfo *)file->private_data;
466
467 xid = GetXid();
468
469 cifs_sb = CIFS_SB(inode->i_sb);
470 pTcon = cifs_sb->tcon;
471 if (pSMBFile) {
472 pSMBFile->closePend = TRUE;
473 write_lock(&file->f_owner.lock);
474 if (pTcon) {
475 /* no sense reconnecting to close a file that is
476 already closed */
477 if (pTcon->tidStatus != CifsNeedReconnect) {
Steve French23e7dd72005-10-20 13:44:56 -0700478 int timeout = 2;
479 while((atomic_read(&pSMBFile->wrtPending) != 0)
480 && (timeout < 1000) ) {
481 /* Give write a better chance to get to
482 server ahead of the close. We do not
483 want to add a wait_q here as it would
484 increase the memory utilization as
485 the struct would be in each open file,
486 but this should give enough time to
487 clear the socket */
Steve Frenchc119b872005-11-18 12:27:27 -0800488 write_unlock(&file->f_owner.lock);
Steve French23e7dd72005-10-20 13:44:56 -0700489 cERROR(1,("close with pending writes"));
490 msleep(timeout);
Steve Frenchc119b872005-11-18 12:27:27 -0800491 write_lock(&file->f_owner.lock);
Steve French23e7dd72005-10-20 13:44:56 -0700492 timeout *= 4;
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 write_unlock(&file->f_owner.lock);
495 rc = CIFSSMBClose(xid, pTcon,
496 pSMBFile->netfid);
497 write_lock(&file->f_owner.lock);
498 }
499 }
Steve Frenchcbe04762005-04-28 22:41:05 -0700500 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 list_del(&pSMBFile->flist);
502 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700503 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 write_unlock(&file->f_owner.lock);
505 kfree(pSMBFile->search_resume_name);
506 kfree(file->private_data);
507 file->private_data = NULL;
508 } else
509 rc = -EBADF;
510
511 if (list_empty(&(CIFS_I(inode)->openFileList))) {
512 cFYI(1, ("closing last open instance for inode %p", inode));
513 /* if the file is not open we do not know if we can cache info
514 on this inode, much less write behind and read ahead */
515 CIFS_I(inode)->clientCanCacheRead = FALSE;
516 CIFS_I(inode)->clientCanCacheAll = FALSE;
517 }
518 if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
519 rc = CIFS_I(inode)->write_behind_rc;
520 FreeXid(xid);
521 return rc;
522}
523
524int cifs_closedir(struct inode *inode, struct file *file)
525{
526 int rc = 0;
527 int xid;
528 struct cifsFileInfo *pCFileStruct =
529 (struct cifsFileInfo *)file->private_data;
530 char *ptmp;
531
532 cFYI(1, ("Closedir inode = 0x%p with ", inode));
533
534 xid = GetXid();
535
536 if (pCFileStruct) {
537 struct cifsTconInfo *pTcon;
538 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
539
540 pTcon = cifs_sb->tcon;
541
542 cFYI(1, ("Freeing private data in close dir"));
Steve French31ca3bc2005-04-28 22:41:11 -0700543 if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
544 (pCFileStruct->invalidHandle == FALSE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 pCFileStruct->invalidHandle = TRUE;
546 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
547 cFYI(1, ("Closing uncompleted readdir with rc %d",
548 rc));
549 /* not much we can do if it fails anyway, ignore rc */
550 rc = 0;
551 }
552 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
553 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800554 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000556 if(pCFileStruct->srch_inf.smallBuf)
557 cifs_small_buf_release(ptmp);
558 else
559 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
561 ptmp = pCFileStruct->search_resume_name;
562 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800563 cFYI(1, ("closedir free resume name"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 pCFileStruct->search_resume_name = NULL;
565 kfree(ptmp);
566 }
567 kfree(file->private_data);
568 file->private_data = NULL;
569 }
570 /* BB can we lock the filestruct while this is going on? */
571 FreeXid(xid);
572 return rc;
573}
574
575int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
576{
577 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 __u32 numLock = 0;
579 __u32 numUnlock = 0;
580 __u64 length;
581 int wait_flag = FALSE;
582 struct cifs_sb_info *cifs_sb;
583 struct cifsTconInfo *pTcon;
Steve French08547b02006-02-28 22:39:25 +0000584 __u16 netfid;
585 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587 length = 1 + pfLock->fl_end - pfLock->fl_start;
588 rc = -EACCES;
589 xid = GetXid();
590
591 cFYI(1, ("Lock parm: 0x%x flockflags: "
592 "0x%x flocktype: 0x%x start: %lld end: %lld",
593 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
594 pfLock->fl_end));
595
596 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000597 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000599 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000601 cFYI(1, ("Blocking lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 wait_flag = TRUE;
603 }
604 if (pfLock->fl_flags & FL_ACCESS)
605 cFYI(1, ("Process suspended by mandatory locking - "
606 "not implemented yet "));
607 if (pfLock->fl_flags & FL_LEASE)
608 cFYI(1, ("Lease on file - not implemented yet"));
609 if (pfLock->fl_flags &
610 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
611 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
612
613 if (pfLock->fl_type == F_WRLCK) {
614 cFYI(1, ("F_WRLCK "));
615 numLock = 1;
616 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000617 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000619 /* Check if unlock includes more than
620 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000622 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 lockType |= LOCKING_ANDX_SHARED_LOCK;
624 numLock = 1;
625 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000626 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 numLock = 1;
628 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000629 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 lockType |= LOCKING_ANDX_SHARED_LOCK;
631 numLock = 1;
632 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000633 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
636 pTcon = cifs_sb->tcon;
637
638 if (file->private_data == NULL) {
639 FreeXid(xid);
640 return -EBADF;
641 }
Steve French08547b02006-02-28 22:39:25 +0000642 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Steve French08547b02006-02-28 22:39:25 +0000644
645 /* BB add code here to normalize offset and length to
646 account for negative length which we can not accept over the
647 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (IS_GETLK(cmd)) {
Steve French08547b02006-02-28 22:39:25 +0000649 if(experimEnabled &&
Steve French82940a42006-03-02 03:24:57 +0000650 (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
651 (CIFS_UNIX_FCNTL_CAP &
652 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
Steve French08547b02006-02-28 22:39:25 +0000653 int posix_lock_type;
654 if(lockType & LOCKING_ANDX_SHARED_LOCK)
655 posix_lock_type = CIFS_RDLCK;
656 else
657 posix_lock_type = CIFS_WRLCK;
658 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000659 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000660 posix_lock_type, wait_flag);
661 FreeXid(xid);
662 return rc;
663 }
664
665 /* BB we could chain these into one lock request BB */
666 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
667 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (rc == 0) {
Steve French08547b02006-02-28 22:39:25 +0000669 rc = CIFSSMBLock(xid, pTcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 pfLock->fl_start, 1 /* numUnlock */ ,
671 0 /* numLock */ , lockType,
672 0 /* wait flag */ );
673 pfLock->fl_type = F_UNLCK;
674 if (rc != 0)
675 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000676 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 rc = 0;
678
679 } else {
680 /* if rc == ERR_SHARING_VIOLATION ? */
681 rc = 0; /* do not change lock type to unlock
682 since range in use */
683 }
684
685 FreeXid(xid);
686 return rc;
687 }
Steve French08547b02006-02-28 22:39:25 +0000688 if (experimEnabled &&
Steve French82940a42006-03-02 03:24:57 +0000689 (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
690 (CIFS_UNIX_FCNTL_CAP &
691 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
Steve French08547b02006-02-28 22:39:25 +0000692 int posix_lock_type;
693 if(lockType & LOCKING_ANDX_SHARED_LOCK)
694 posix_lock_type = CIFS_RDLCK;
695 else
696 posix_lock_type = CIFS_WRLCK;
697
698 if(numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000699 posix_lock_type = CIFS_UNLCK;
Steve French08547b02006-02-28 22:39:25 +0000700 else if(numLock == 0) {
701 /* if no lock or unlock then nothing
702 to do since we do not know what it is */
703 FreeXid(xid);
704 return -EOPNOTSUPP;
705 }
706 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000707 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000708 posix_lock_type, wait_flag);
709 } else
710 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
711 numUnlock, numLock, lockType, wait_flag);
Steve Frenchd634cc12005-08-26 14:42:59 -0500712 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 posix_lock_file_wait(file, pfLock);
714 FreeXid(xid);
715 return rc;
716}
717
718ssize_t cifs_user_write(struct file *file, const char __user *write_data,
719 size_t write_size, loff_t *poffset)
720{
721 int rc = 0;
722 unsigned int bytes_written = 0;
723 unsigned int total_written;
724 struct cifs_sb_info *cifs_sb;
725 struct cifsTconInfo *pTcon;
726 int xid, long_op;
727 struct cifsFileInfo *open_file;
728
729 if (file->f_dentry == NULL)
730 return -EBADF;
731
732 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
733 if (cifs_sb == NULL)
734 return -EBADF;
735
736 pTcon = cifs_sb->tcon;
737
738 /* cFYI(1,
739 (" write %d bytes to offset %lld of %s", write_size,
740 *poffset, file->f_dentry->d_name.name)); */
741
742 if (file->private_data == NULL)
743 return -EBADF;
744 else
745 open_file = (struct cifsFileInfo *) file->private_data;
746
747 xid = GetXid();
748 if (file->f_dentry->d_inode == NULL) {
749 FreeXid(xid);
750 return -EBADF;
751 }
752
753 if (*poffset > file->f_dentry->d_inode->i_size)
754 long_op = 2; /* writes past end of file can take a long time */
755 else
756 long_op = 1;
757
758 for (total_written = 0; write_size > total_written;
759 total_written += bytes_written) {
760 rc = -EAGAIN;
761 while (rc == -EAGAIN) {
762 if (file->private_data == NULL) {
763 /* file has been closed on us */
764 FreeXid(xid);
765 /* if we have gotten here we have written some data
766 and blocked, and the file has been freed on us while
767 we blocked so return what we managed to write */
768 return total_written;
769 }
770 if (open_file->closePend) {
771 FreeXid(xid);
772 if (total_written)
773 return total_written;
774 else
775 return -EBADF;
776 }
777 if (open_file->invalidHandle) {
778 if ((file->f_dentry == NULL) ||
779 (file->f_dentry->d_inode == NULL)) {
780 FreeXid(xid);
781 return total_written;
782 }
783 /* we could deadlock if we called
784 filemap_fdatawait from here so tell
785 reopen_file not to flush data to server
786 now */
787 rc = cifs_reopen_file(file->f_dentry->d_inode,
788 file, FALSE);
789 if (rc != 0)
790 break;
791 }
792
793 rc = CIFSSMBWrite(xid, pTcon,
794 open_file->netfid,
795 min_t(const int, cifs_sb->wsize,
796 write_size - total_written),
797 *poffset, &bytes_written,
798 NULL, write_data + total_written, long_op);
799 }
800 if (rc || (bytes_written == 0)) {
801 if (total_written)
802 break;
803 else {
804 FreeXid(xid);
805 return rc;
806 }
807 } else
808 *poffset += bytes_written;
809 long_op = FALSE; /* subsequent writes fast -
810 15 seconds is plenty */
811 }
812
Steve Frencha4544342005-08-24 13:59:35 -0700813 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 /* since the write may have blocked check these pointers again */
816 if (file->f_dentry) {
817 if (file->f_dentry->d_inode) {
818 struct inode *inode = file->f_dentry->d_inode;
819 inode->i_ctime = inode->i_mtime =
820 current_fs_time(inode->i_sb);
821 if (total_written > 0) {
822 if (*poffset > file->f_dentry->d_inode->i_size)
823 i_size_write(file->f_dentry->d_inode,
824 *poffset);
825 }
826 mark_inode_dirty_sync(file->f_dentry->d_inode);
827 }
828 }
829 FreeXid(xid);
830 return total_written;
831}
832
833static ssize_t cifs_write(struct file *file, const char *write_data,
834 size_t write_size, loff_t *poffset)
835{
836 int rc = 0;
837 unsigned int bytes_written = 0;
838 unsigned int total_written;
839 struct cifs_sb_info *cifs_sb;
840 struct cifsTconInfo *pTcon;
841 int xid, long_op;
842 struct cifsFileInfo *open_file;
843
844 if (file->f_dentry == NULL)
845 return -EBADF;
846
847 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
848 if (cifs_sb == NULL)
849 return -EBADF;
850
851 pTcon = cifs_sb->tcon;
852
Steve Frenchab2f2182005-09-15 20:44:50 -0700853 cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
854 *poffset, file->f_dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
856 if (file->private_data == NULL)
857 return -EBADF;
858 else
859 open_file = (struct cifsFileInfo *)file->private_data;
860
861 xid = GetXid();
862 if (file->f_dentry->d_inode == NULL) {
863 FreeXid(xid);
864 return -EBADF;
865 }
866
867 if (*poffset > file->f_dentry->d_inode->i_size)
868 long_op = 2; /* writes past end of file can take a long time */
869 else
870 long_op = 1;
871
872 for (total_written = 0; write_size > total_written;
873 total_written += bytes_written) {
874 rc = -EAGAIN;
875 while (rc == -EAGAIN) {
876 if (file->private_data == NULL) {
877 /* file has been closed on us */
878 FreeXid(xid);
879 /* if we have gotten here we have written some data
880 and blocked, and the file has been freed on us
881 while we blocked so return what we managed to
882 write */
883 return total_written;
884 }
885 if (open_file->closePend) {
886 FreeXid(xid);
887 if (total_written)
888 return total_written;
889 else
890 return -EBADF;
891 }
892 if (open_file->invalidHandle) {
893 if ((file->f_dentry == NULL) ||
894 (file->f_dentry->d_inode == NULL)) {
895 FreeXid(xid);
896 return total_written;
897 }
898 /* we could deadlock if we called
899 filemap_fdatawait from here so tell
900 reopen_file not to flush data to
901 server now */
902 rc = cifs_reopen_file(file->f_dentry->d_inode,
903 file, FALSE);
904 if (rc != 0)
905 break;
906 }
Steve French60808232006-04-22 15:53:05 +0000907 if(experimEnabled || (pTcon->ses->server->secMode &
Steve Frenchec637e32005-12-12 20:53:18 -0800908 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) {
Steve French3e844692005-10-03 13:37:24 -0700909 struct kvec iov[2];
910 unsigned int len;
911
Steve French0ae0efa2005-10-10 10:57:19 -0700912 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -0700913 write_size - total_written);
914 /* iov[0] is reserved for smb header */
915 iov[1].iov_base = (char *)write_data +
916 total_written;
917 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500918 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -0700919 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500920 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -0700921 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500922 } else
Steve French60808232006-04-22 15:53:05 +0000923 rc = CIFSSMBWrite(xid, pTcon,
924 open_file->netfid,
925 min_t(const int, cifs_sb->wsize,
926 write_size - total_written),
927 *poffset, &bytes_written,
928 write_data + total_written,
929 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
931 if (rc || (bytes_written == 0)) {
932 if (total_written)
933 break;
934 else {
935 FreeXid(xid);
936 return rc;
937 }
938 } else
939 *poffset += bytes_written;
940 long_op = FALSE; /* subsequent writes fast -
941 15 seconds is plenty */
942 }
943
Steve Frencha4544342005-08-24 13:59:35 -0700944 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 /* since the write may have blocked check these pointers again */
947 if (file->f_dentry) {
948 if (file->f_dentry->d_inode) {
949 file->f_dentry->d_inode->i_ctime =
950 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
951 if (total_written > 0) {
952 if (*poffset > file->f_dentry->d_inode->i_size)
953 i_size_write(file->f_dentry->d_inode,
954 *poffset);
955 }
956 mark_inode_dirty_sync(file->f_dentry->d_inode);
957 }
958 }
959 FreeXid(xid);
960 return total_written;
961}
962
Steve Frenchdd99cd82005-10-05 19:32:49 -0700963struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -0700964{
965 struct cifsFileInfo *open_file;
Steve Frenchdd99cd82005-10-05 19:32:49 -0700966 int rc;
Steve French6148a742005-10-05 12:23:19 -0700967
Steve French60808232006-04-22 15:53:05 +0000968 /* Having a null inode here (because mapping->host was set to zero by
969 the VFS or MM) should not happen but we had reports of on oops (due to
970 it being zero) during stress testcases so we need to check for it */
971
972 if(cifs_inode == NULL) {
973 cERROR(1,("Null inode passed to cifs_writeable_file"));
974 dump_stack();
975 return NULL;
976 }
977
Steve French6148a742005-10-05 12:23:19 -0700978 read_lock(&GlobalSMBSeslock);
979 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
980 if (open_file->closePend)
981 continue;
982 if (open_file->pfile &&
983 ((open_file->pfile->f_flags & O_RDWR) ||
984 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -0700985 atomic_inc(&open_file->wrtPending);
Steve French6148a742005-10-05 12:23:19 -0700986 read_unlock(&GlobalSMBSeslock);
Steve French0ae0efa2005-10-10 10:57:19 -0700987 if((open_file->invalidHandle) &&
Steve French23e7dd72005-10-20 13:44:56 -0700988 (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
Steve Frenchdd99cd82005-10-05 19:32:49 -0700989 rc = cifs_reopen_file(&cifs_inode->vfs_inode,
Steve French37c0eb42005-10-05 14:50:29 -0700990 open_file->pfile, FALSE);
991 /* if it fails, try another handle - might be */
992 /* dangerous to hold up writepages with retry */
993 if(rc) {
Steve French4a771182005-10-05 15:14:33 -0700994 cFYI(1,("failed on reopen file in wp"));
Steve French37c0eb42005-10-05 14:50:29 -0700995 read_lock(&GlobalSMBSeslock);
Steve French23e7dd72005-10-20 13:44:56 -0700996 /* can not use this handle, no write
997 pending on this one after all */
998 atomic_dec
999 (&open_file->wrtPending);
Steve French37c0eb42005-10-05 14:50:29 -07001000 continue;
1001 }
1002 }
Steve French6148a742005-10-05 12:23:19 -07001003 return open_file;
1004 }
1005 }
1006 read_unlock(&GlobalSMBSeslock);
1007 return NULL;
1008}
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1011{
1012 struct address_space *mapping = page->mapping;
1013 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1014 char *write_data;
1015 int rc = -EFAULT;
1016 int bytes_written = 0;
1017 struct cifs_sb_info *cifs_sb;
1018 struct cifsTconInfo *pTcon;
1019 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001020 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 if (!mapping || !mapping->host)
1023 return -EFAULT;
1024
1025 inode = page->mapping->host;
1026 cifs_sb = CIFS_SB(inode->i_sb);
1027 pTcon = cifs_sb->tcon;
1028
1029 offset += (loff_t)from;
1030 write_data = kmap(page);
1031 write_data += from;
1032
1033 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1034 kunmap(page);
1035 return -EIO;
1036 }
1037
1038 /* racing with truncate? */
1039 if (offset > mapping->host->i_size) {
1040 kunmap(page);
1041 return 0; /* don't care */
1042 }
1043
1044 /* check to make sure that we are not extending the file */
1045 if (mapping->host->i_size - offset < (loff_t)to)
1046 to = (unsigned)(mapping->host->i_size - offset);
1047
Steve French6148a742005-10-05 12:23:19 -07001048 open_file = find_writable_file(CIFS_I(mapping->host));
1049 if (open_file) {
1050 bytes_written = cifs_write(open_file->pfile, write_data,
1051 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001052 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001054 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
1055 if ((bytes_written > 0) && (offset)) {
1056 rc = 0;
1057 } else if (bytes_written < 0) {
1058 if (rc != -EBADF)
1059 rc = bytes_written;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
Steve French6148a742005-10-05 12:23:19 -07001061 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 cFYI(1, ("No writeable filehandles for inode"));
1063 rc = -EIO;
1064 }
1065
1066 kunmap(page);
1067 return rc;
1068}
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001071 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Steve French37c0eb42005-10-05 14:50:29 -07001073 struct backing_dev_info *bdi = mapping->backing_dev_info;
1074 unsigned int bytes_to_write;
1075 unsigned int bytes_written;
1076 struct cifs_sb_info *cifs_sb;
1077 int done = 0;
1078 pgoff_t end = -1;
1079 pgoff_t index;
1080 int is_range = 0;
1081 struct kvec iov[32];
Steve French84d2f072005-10-12 15:32:05 -07001082 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001083 int n_iov = 0;
1084 pgoff_t next;
1085 int nr_pages;
1086 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001087 struct cifsFileInfo *open_file;
Steve French37c0eb42005-10-05 14:50:29 -07001088 struct page *page;
1089 struct pagevec pvec;
1090 int rc = 0;
1091 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 int xid;
1093
Steve French37c0eb42005-10-05 14:50:29 -07001094 cifs_sb = CIFS_SB(mapping->host->i_sb);
1095
1096 /*
1097 * If wsize is smaller that the page cache size, default to writing
1098 * one page at a time via cifs_writepage
1099 */
1100 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1101 return generic_writepages(mapping, wbc);
1102
Steve French4a771182005-10-05 15:14:33 -07001103 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1104 if(cifs_sb->tcon->ses->server->secMode &
1105 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve French60808232006-04-22 15:53:05 +00001106 if(!experimEnabled)
1107 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001108
Steve French37c0eb42005-10-05 14:50:29 -07001109 /*
1110 * BB: Is this meaningful for a non-block-device file system?
1111 * If it is, we should test it again after we do I/O
1112 */
1113 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1114 wbc->encountered_congestion = 1;
1115 return 0;
1116 }
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 xid = GetXid();
1119
Steve French37c0eb42005-10-05 14:50:29 -07001120 pagevec_init(&pvec, 0);
1121 if (wbc->sync_mode == WB_SYNC_NONE)
1122 index = mapping->writeback_index; /* Start from prev offset */
1123 else {
1124 index = 0;
1125 scanned = 1;
1126 }
1127 if (wbc->start || wbc->end) {
1128 index = wbc->start >> PAGE_CACHE_SHIFT;
1129 end = wbc->end >> PAGE_CACHE_SHIFT;
1130 is_range = 1;
1131 scanned = 1;
1132 }
1133retry:
1134 while (!done && (index <= end) &&
1135 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1136 PAGECACHE_TAG_DIRTY,
1137 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1138 int first;
1139 unsigned int i;
1140
Steve French37c0eb42005-10-05 14:50:29 -07001141 first = -1;
1142 next = 0;
1143 n_iov = 0;
1144 bytes_to_write = 0;
1145
1146 for (i = 0; i < nr_pages; i++) {
1147 page = pvec.pages[i];
1148 /*
1149 * At this point we hold neither mapping->tree_lock nor
1150 * lock on the page itself: the page may be truncated or
1151 * invalidated (changing page->mapping to NULL), or even
1152 * swizzled back from swapper_space to tmpfs file
1153 * mapping
1154 */
1155
1156 if (first < 0)
1157 lock_page(page);
1158 else if (TestSetPageLocked(page))
1159 break;
1160
1161 if (unlikely(page->mapping != mapping)) {
1162 unlock_page(page);
1163 break;
1164 }
1165
1166 if (unlikely(is_range) && (page->index > end)) {
1167 done = 1;
1168 unlock_page(page);
1169 break;
1170 }
1171
1172 if (next && (page->index != next)) {
1173 /* Not next consecutive page */
1174 unlock_page(page);
1175 break;
1176 }
1177
1178 if (wbc->sync_mode != WB_SYNC_NONE)
1179 wait_on_page_writeback(page);
1180
1181 if (PageWriteback(page) ||
1182 !test_clear_page_dirty(page)) {
1183 unlock_page(page);
1184 break;
1185 }
Steve French84d2f072005-10-12 15:32:05 -07001186
1187 if (page_offset(page) >= mapping->host->i_size) {
1188 done = 1;
1189 unlock_page(page);
1190 break;
1191 }
1192
Steve French37c0eb42005-10-05 14:50:29 -07001193 /*
1194 * BB can we get rid of this? pages are held by pvec
1195 */
1196 page_cache_get(page);
1197
Steve French84d2f072005-10-12 15:32:05 -07001198 len = min(mapping->host->i_size - page_offset(page),
1199 (loff_t)PAGE_CACHE_SIZE);
1200
Steve French37c0eb42005-10-05 14:50:29 -07001201 /* reserve iov[0] for the smb header */
1202 n_iov++;
1203 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001204 iov[n_iov].iov_len = len;
1205 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001206
1207 if (first < 0) {
1208 first = i;
1209 offset = page_offset(page);
1210 }
1211 next = page->index + 1;
1212 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1213 break;
1214 }
1215 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001216 /* Search for a writable handle every time we call
1217 * CIFSSMBWrite2. We can't rely on the last handle
1218 * we used to still be valid
1219 */
1220 open_file = find_writable_file(CIFS_I(mapping->host));
1221 if (!open_file) {
1222 cERROR(1, ("No writable handles for inode"));
1223 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001224 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001225 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1226 open_file->netfid,
1227 bytes_to_write, offset,
1228 &bytes_written, iov, n_iov,
1229 1);
1230 atomic_dec(&open_file->wrtPending);
1231 if (rc || bytes_written < bytes_to_write) {
1232 cERROR(1,("Write2 ret %d, written = %d",
1233 rc, bytes_written));
1234 /* BB what if continued retry is
1235 requested via mount flags? */
1236 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001237 } else {
1238 cifs_stats_bytes_written(cifs_sb->tcon,
1239 bytes_written);
1240 }
Steve French37c0eb42005-10-05 14:50:29 -07001241 }
1242 for (i = 0; i < n_iov; i++) {
1243 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001244 /* Should we also set page error on
1245 success rc but too little data written? */
1246 /* BB investigate retry logic on temporary
1247 server crash cases and how recovery works
1248 when page marked as error */
1249 if(rc)
1250 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001251 kunmap(page);
1252 unlock_page(page);
1253 page_cache_release(page);
1254 }
1255 if ((wbc->nr_to_write -= n_iov) <= 0)
1256 done = 1;
1257 index = next;
1258 }
1259 pagevec_release(&pvec);
1260 }
1261 if (!scanned && !done) {
1262 /*
1263 * We hit the last page and there is more work to be done: wrap
1264 * back to the start of the file
1265 */
1266 scanned = 1;
1267 index = 0;
1268 goto retry;
1269 }
1270 if (!is_range)
1271 mapping->writeback_index = index;
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 FreeXid(xid);
Steve French37c0eb42005-10-05 14:50:29 -07001274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 return rc;
1276}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278static int cifs_writepage(struct page* page, struct writeback_control *wbc)
1279{
1280 int rc = -EFAULT;
1281 int xid;
1282
1283 xid = GetXid();
1284/* BB add check for wbc flags */
1285 page_cache_get(page);
1286 if (!PageUptodate(page)) {
1287 cFYI(1, ("ppw - page not up to date"));
1288 }
1289
1290 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1291 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1292 unlock_page(page);
1293 page_cache_release(page);
1294 FreeXid(xid);
1295 return rc;
1296}
1297
1298static int cifs_commit_write(struct file *file, struct page *page,
1299 unsigned offset, unsigned to)
1300{
1301 int xid;
1302 int rc = 0;
1303 struct inode *inode = page->mapping->host;
1304 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1305 char *page_data;
1306
1307 xid = GetXid();
1308 cFYI(1, ("commit write for page %p up to position %lld for %d",
1309 page, position, to));
1310 if (position > inode->i_size) {
1311 i_size_write(inode, position);
1312 /* if (file->private_data == NULL) {
1313 rc = -EBADF;
1314 } else {
1315 open_file = (struct cifsFileInfo *)file->private_data;
1316 cifs_sb = CIFS_SB(inode->i_sb);
1317 rc = -EAGAIN;
1318 while (rc == -EAGAIN) {
1319 if ((open_file->invalidHandle) &&
1320 (!open_file->closePend)) {
1321 rc = cifs_reopen_file(
1322 file->f_dentry->d_inode, file);
1323 if (rc != 0)
1324 break;
1325 }
1326 if (!open_file->closePend) {
1327 rc = CIFSSMBSetFileSize(xid,
1328 cifs_sb->tcon, position,
1329 open_file->netfid,
1330 open_file->pid, FALSE);
1331 } else {
1332 rc = -EBADF;
1333 break;
1334 }
1335 }
1336 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1337 } */
1338 }
1339 if (!PageUptodate(page)) {
1340 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1341 /* can not rely on (or let) writepage write this data */
1342 if (to < offset) {
1343 cFYI(1, ("Illegal offsets, can not copy from %d to %d",
1344 offset, to));
1345 FreeXid(xid);
1346 return rc;
1347 }
1348 /* this is probably better than directly calling
1349 partialpage_write since in this function the file handle is
1350 known which we might as well leverage */
1351 /* BB check if anything else missing out of ppw
1352 such as updating last write time */
1353 page_data = kmap(page);
1354 rc = cifs_write(file, page_data + offset, to-offset,
1355 &position);
1356 if (rc > 0)
1357 rc = 0;
1358 /* else if (rc < 0) should we set writebehind rc? */
1359 kunmap(page);
1360 } else {
1361 set_page_dirty(page);
1362 }
1363
1364 FreeXid(xid);
1365 return rc;
1366}
1367
1368int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1369{
1370 int xid;
1371 int rc = 0;
1372 struct inode *inode = file->f_dentry->d_inode;
1373
1374 xid = GetXid();
1375
1376 cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
1377 dentry->d_name.name, datasync));
1378
1379 rc = filemap_fdatawrite(inode->i_mapping);
1380 if (rc == 0)
1381 CIFS_I(inode)->write_behind_rc = 0;
1382 FreeXid(xid);
1383 return rc;
1384}
1385
NeilBrown3978d7172006-03-26 01:37:17 -08001386/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 struct address_space *mapping;
1389 struct inode *inode;
1390 unsigned long index = page->index;
1391 unsigned int rpages = 0;
1392 int rc = 0;
1393
1394 cFYI(1, ("sync page %p",page));
1395 mapping = page->mapping;
1396 if (!mapping)
1397 return 0;
1398 inode = mapping->host;
1399 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001400 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402/* fill in rpages then
1403 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1404
1405/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
1406
NeilBrown3978d7172006-03-26 01:37:17 -08001407#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (rc < 0)
1409 return rc;
1410 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001411#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412} */
1413
1414/*
1415 * As file closes, flush all cached write data for this inode checking
1416 * for write behind errors.
1417 */
1418int cifs_flush(struct file *file)
1419{
1420 struct inode * inode = file->f_dentry->d_inode;
1421 int rc = 0;
1422
1423 /* Rather than do the steps manually:
1424 lock the inode for writing
1425 loop through pages looking for write behind data (dirty pages)
1426 coalesce into contiguous 16K (or smaller) chunks to write to server
1427 send to server (prefer in parallel)
1428 deal with writebehind errors
1429 unlock inode for writing
1430 filemapfdatawrite appears easier for the time being */
1431
1432 rc = filemap_fdatawrite(inode->i_mapping);
1433 if (!rc) /* reset wb rc if we were able to write out dirty pages */
1434 CIFS_I(inode)->write_behind_rc = 0;
1435
1436 cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
1437
1438 return rc;
1439}
1440
1441ssize_t cifs_user_read(struct file *file, char __user *read_data,
1442 size_t read_size, loff_t *poffset)
1443{
1444 int rc = -EACCES;
1445 unsigned int bytes_read = 0;
1446 unsigned int total_read = 0;
1447 unsigned int current_read_size;
1448 struct cifs_sb_info *cifs_sb;
1449 struct cifsTconInfo *pTcon;
1450 int xid;
1451 struct cifsFileInfo *open_file;
1452 char *smb_read_data;
1453 char __user *current_offset;
1454 struct smb_com_read_rsp *pSMBr;
1455
1456 xid = GetXid();
1457 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1458 pTcon = cifs_sb->tcon;
1459
1460 if (file->private_data == NULL) {
1461 FreeXid(xid);
1462 return -EBADF;
1463 }
1464 open_file = (struct cifsFileInfo *)file->private_data;
1465
1466 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1467 cFYI(1, ("attempting read on write only file instance"));
1468 }
1469 for (total_read = 0, current_offset = read_data;
1470 read_size > total_read;
1471 total_read += bytes_read, current_offset += bytes_read) {
1472 current_read_size = min_t(const int, read_size - total_read,
1473 cifs_sb->rsize);
1474 rc = -EAGAIN;
1475 smb_read_data = NULL;
1476 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001477 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if ((open_file->invalidHandle) &&
1479 (!open_file->closePend)) {
1480 rc = cifs_reopen_file(file->f_dentry->d_inode,
1481 file, TRUE);
1482 if (rc != 0)
1483 break;
1484 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001485 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001486 open_file->netfid,
1487 current_read_size, *poffset,
1488 &bytes_read, &smb_read_data,
1489 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001492 if (copy_to_user(current_offset,
1493 smb_read_data +
1494 4 /* RFC1001 length field */ +
1495 le16_to_cpu(pSMBr->DataOffset),
1496 bytes_read)) {
1497 rc = -EFAULT;
1498 }
1499
Steve Frenchec637e32005-12-12 20:53:18 -08001500 if(buf_type == CIFS_SMALL_BUFFER)
1501 cifs_small_buf_release(smb_read_data);
1502 else if(buf_type == CIFS_LARGE_BUFFER)
1503 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 smb_read_data = NULL;
1505 }
1506 }
1507 if (rc || (bytes_read == 0)) {
1508 if (total_read) {
1509 break;
1510 } else {
1511 FreeXid(xid);
1512 return rc;
1513 }
1514 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001515 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 *poffset += bytes_read;
1517 }
1518 }
1519 FreeXid(xid);
1520 return total_read;
1521}
1522
1523
1524static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1525 loff_t *poffset)
1526{
1527 int rc = -EACCES;
1528 unsigned int bytes_read = 0;
1529 unsigned int total_read;
1530 unsigned int current_read_size;
1531 struct cifs_sb_info *cifs_sb;
1532 struct cifsTconInfo *pTcon;
1533 int xid;
1534 char *current_offset;
1535 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001536 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 xid = GetXid();
1539 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1540 pTcon = cifs_sb->tcon;
1541
1542 if (file->private_data == NULL) {
1543 FreeXid(xid);
1544 return -EBADF;
1545 }
1546 open_file = (struct cifsFileInfo *)file->private_data;
1547
1548 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1549 cFYI(1, ("attempting read on write only file instance"));
1550
1551 for (total_read = 0, current_offset = read_data;
1552 read_size > total_read;
1553 total_read += bytes_read, current_offset += bytes_read) {
1554 current_read_size = min_t(const int, read_size - total_read,
1555 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001556 /* For windows me and 9x we do not want to request more
1557 than it negotiated since it will refuse the read then */
1558 if((pTcon->ses) &&
1559 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1560 current_read_size = min_t(const int, current_read_size,
1561 pTcon->ses->server->maxBuf - 128);
1562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 rc = -EAGAIN;
1564 while (rc == -EAGAIN) {
1565 if ((open_file->invalidHandle) &&
1566 (!open_file->closePend)) {
1567 rc = cifs_reopen_file(file->f_dentry->d_inode,
1568 file, TRUE);
1569 if (rc != 0)
1570 break;
1571 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001572 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001573 open_file->netfid,
1574 current_read_size, *poffset,
1575 &bytes_read, &current_offset,
1576 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
1578 if (rc || (bytes_read == 0)) {
1579 if (total_read) {
1580 break;
1581 } else {
1582 FreeXid(xid);
1583 return rc;
1584 }
1585 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001586 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 *poffset += bytes_read;
1588 }
1589 }
1590 FreeXid(xid);
1591 return total_read;
1592}
1593
1594int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1595{
1596 struct dentry *dentry = file->f_dentry;
1597 int rc, xid;
1598
1599 xid = GetXid();
1600 rc = cifs_revalidate(dentry);
1601 if (rc) {
1602 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1603 FreeXid(xid);
1604 return rc;
1605 }
1606 rc = generic_file_mmap(file, vma);
1607 FreeXid(xid);
1608 return rc;
1609}
1610
1611
1612static void cifs_copy_cache_pages(struct address_space *mapping,
1613 struct list_head *pages, int bytes_read, char *data,
1614 struct pagevec *plru_pvec)
1615{
1616 struct page *page;
1617 char *target;
1618
1619 while (bytes_read > 0) {
1620 if (list_empty(pages))
1621 break;
1622
1623 page = list_entry(pages->prev, struct page, lru);
1624 list_del(&page->lru);
1625
1626 if (add_to_page_cache(page, mapping, page->index,
1627 GFP_KERNEL)) {
1628 page_cache_release(page);
1629 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001630 data += PAGE_CACHE_SIZE;
1631 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 continue;
1633 }
1634
1635 target = kmap_atomic(page,KM_USER0);
1636
1637 if (PAGE_CACHE_SIZE > bytes_read) {
1638 memcpy(target, data, bytes_read);
1639 /* zero the tail end of this partial page */
1640 memset(target + bytes_read, 0,
1641 PAGE_CACHE_SIZE - bytes_read);
1642 bytes_read = 0;
1643 } else {
1644 memcpy(target, data, PAGE_CACHE_SIZE);
1645 bytes_read -= PAGE_CACHE_SIZE;
1646 }
1647 kunmap_atomic(target, KM_USER0);
1648
1649 flush_dcache_page(page);
1650 SetPageUptodate(page);
1651 unlock_page(page);
1652 if (!pagevec_add(plru_pvec, page))
1653 __pagevec_lru_add(plru_pvec);
1654 data += PAGE_CACHE_SIZE;
1655 }
1656 return;
1657}
1658
1659static int cifs_readpages(struct file *file, struct address_space *mapping,
1660 struct list_head *page_list, unsigned num_pages)
1661{
1662 int rc = -EACCES;
1663 int xid;
1664 loff_t offset;
1665 struct page *page;
1666 struct cifs_sb_info *cifs_sb;
1667 struct cifsTconInfo *pTcon;
1668 int bytes_read = 0;
1669 unsigned int read_size,i;
1670 char *smb_read_data = NULL;
1671 struct smb_com_read_rsp *pSMBr;
1672 struct pagevec lru_pvec;
1673 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001674 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
1676 xid = GetXid();
1677 if (file->private_data == NULL) {
1678 FreeXid(xid);
1679 return -EBADF;
1680 }
1681 open_file = (struct cifsFileInfo *)file->private_data;
1682 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1683 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 pagevec_init(&lru_pvec, 0);
1686
1687 for (i = 0; i < num_pages; ) {
1688 unsigned contig_pages;
1689 struct page *tmp_page;
1690 unsigned long expected_index;
1691
1692 if (list_empty(page_list))
1693 break;
1694
1695 page = list_entry(page_list->prev, struct page, lru);
1696 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1697
1698 /* count adjacent pages that we will read into */
1699 contig_pages = 0;
1700 expected_index =
1701 list_entry(page_list->prev, struct page, lru)->index;
1702 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1703 if (tmp_page->index == expected_index) {
1704 contig_pages++;
1705 expected_index++;
1706 } else
1707 break;
1708 }
1709 if (contig_pages + i > num_pages)
1710 contig_pages = num_pages - i;
1711
1712 /* for reads over a certain size could initiate async
1713 read ahead */
1714
1715 read_size = contig_pages * PAGE_CACHE_SIZE;
1716 /* Read size needs to be in multiples of one page */
1717 read_size = min_t(const unsigned int, read_size,
1718 cifs_sb->rsize & PAGE_CACHE_MASK);
1719
1720 rc = -EAGAIN;
1721 while (rc == -EAGAIN) {
1722 if ((open_file->invalidHandle) &&
1723 (!open_file->closePend)) {
1724 rc = cifs_reopen_file(file->f_dentry->d_inode,
1725 file, TRUE);
1726 if (rc != 0)
1727 break;
1728 }
1729
Steve Frenchbfa0d752005-08-31 21:50:37 -07001730 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001731 open_file->netfid,
1732 read_size, offset,
1733 &bytes_read, &smb_read_data,
1734 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001735 /* BB more RC checks ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (rc== -EAGAIN) {
1737 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001738 if(buf_type == CIFS_SMALL_BUFFER)
1739 cifs_small_buf_release(smb_read_data);
1740 else if(buf_type == CIFS_LARGE_BUFFER)
1741 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 smb_read_data = NULL;
1743 }
1744 }
1745 }
1746 if ((rc < 0) || (smb_read_data == NULL)) {
1747 cFYI(1, ("Read error in readpages: %d", rc));
1748 /* clean up remaing pages off list */
1749 while (!list_empty(page_list) && (i < num_pages)) {
1750 page = list_entry(page_list->prev, struct page,
1751 lru);
1752 list_del(&page->lru);
1753 page_cache_release(page);
1754 }
1755 break;
1756 } else if (bytes_read > 0) {
1757 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1758 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1759 smb_read_data + 4 /* RFC1001 hdr */ +
1760 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1761
1762 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001763 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1765 i++; /* account for partial page */
1766
1767 /* server copy of file can have smaller size
1768 than client */
1769 /* BB do we need to verify this common case ?
1770 this case is ok - if we are at server EOF
1771 we will hit it on next read */
1772
1773 /* while (!list_empty(page_list) && (i < num_pages)) {
1774 page = list_entry(page_list->prev,
1775 struct page, list);
1776 list_del(&page->list);
1777 page_cache_release(page);
1778 }
1779 break; */
1780 }
1781 } else {
1782 cFYI(1, ("No bytes read (%d) at offset %lld . "
1783 "Cleaning remaining pages from readahead list",
1784 bytes_read, offset));
1785 /* BB turn off caching and do new lookup on
1786 file size at server? */
1787 while (!list_empty(page_list) && (i < num_pages)) {
1788 page = list_entry(page_list->prev, struct page,
1789 lru);
1790 list_del(&page->lru);
1791
1792 /* BB removeme - replace with zero of page? */
1793 page_cache_release(page);
1794 }
1795 break;
1796 }
1797 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001798 if(buf_type == CIFS_SMALL_BUFFER)
1799 cifs_small_buf_release(smb_read_data);
1800 else if(buf_type == CIFS_LARGE_BUFFER)
1801 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 smb_read_data = NULL;
1803 }
1804 bytes_read = 0;
1805 }
1806
1807 pagevec_lru_add(&lru_pvec);
1808
1809/* need to free smb_read_data buf before exit */
1810 if (smb_read_data) {
Steve French47c886b2006-01-18 14:20:39 -08001811 if(buf_type == CIFS_SMALL_BUFFER)
1812 cifs_small_buf_release(smb_read_data);
1813 else if(buf_type == CIFS_LARGE_BUFFER)
1814 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 smb_read_data = NULL;
1816 }
1817
1818 FreeXid(xid);
1819 return rc;
1820}
1821
1822static int cifs_readpage_worker(struct file *file, struct page *page,
1823 loff_t *poffset)
1824{
1825 char *read_data;
1826 int rc;
1827
1828 page_cache_get(page);
1829 read_data = kmap(page);
1830 /* for reads over a certain size could initiate async read ahead */
1831
1832 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1833
1834 if (rc < 0)
1835 goto io_error;
1836 else
1837 cFYI(1, ("Bytes read %d ",rc));
1838
1839 file->f_dentry->d_inode->i_atime =
1840 current_fs_time(file->f_dentry->d_inode->i_sb);
1841
1842 if (PAGE_CACHE_SIZE > rc)
1843 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1844
1845 flush_dcache_page(page);
1846 SetPageUptodate(page);
1847 rc = 0;
1848
1849io_error:
1850 kunmap(page);
1851 page_cache_release(page);
1852 return rc;
1853}
1854
1855static int cifs_readpage(struct file *file, struct page *page)
1856{
1857 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1858 int rc = -EACCES;
1859 int xid;
1860
1861 xid = GetXid();
1862
1863 if (file->private_data == NULL) {
1864 FreeXid(xid);
1865 return -EBADF;
1866 }
1867
1868 cFYI(1, ("readpage %p at offset %d 0x%x\n",
1869 page, (int)offset, (int)offset));
1870
1871 rc = cifs_readpage_worker(file, page, &offset);
1872
1873 unlock_page(page);
1874
1875 FreeXid(xid);
1876 return rc;
1877}
1878
1879/* We do not want to update the file size from server for inodes
1880 open for write - to avoid races with writepage extending
1881 the file - in the future we could consider allowing
1882 refreshing the inode only on increases in the file size
1883 but this is tricky to do without racing with writebehind
1884 page caching in the current Linux kernel design */
1885int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1886{
Steve French23e7dd72005-10-20 13:44:56 -07001887 struct cifsFileInfo *open_file = NULL;
1888
1889 if (cifsInode)
1890 open_file = find_writable_file(cifsInode);
1891
1892 if(open_file) {
Steve Frenchc32a0b62006-01-12 14:41:28 -08001893 struct cifs_sb_info *cifs_sb;
1894
Steve French23e7dd72005-10-20 13:44:56 -07001895 /* there is not actually a write pending so let
1896 this handle go free and allow it to
1897 be closable if needed */
1898 atomic_dec(&open_file->wrtPending);
Steve Frenchc32a0b62006-01-12 14:41:28 -08001899
1900 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
1901 if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
1902 /* since no page cache to corrupt on directio
1903 we can change size safely */
1904 return 1;
1905 }
1906
Steve French6148a742005-10-05 12:23:19 -07001907 return 0;
Steve French23e7dd72005-10-20 13:44:56 -07001908 } else
Steve French6148a742005-10-05 12:23:19 -07001909 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910}
1911
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912static int cifs_prepare_write(struct file *file, struct page *page,
1913 unsigned from, unsigned to)
1914{
1915 int rc = 0;
1916 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1917 cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
1918 if (!PageUptodate(page)) {
1919 /* if (to - from != PAGE_CACHE_SIZE) {
1920 void *kaddr = kmap_atomic(page, KM_USER0);
1921 memset(kaddr, 0, from);
1922 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1923 flush_dcache_page(page);
1924 kunmap_atomic(kaddr, KM_USER0);
1925 } */
1926 /* If we are writing a full page it will be up to date,
1927 no need to read from the server */
1928 if ((to == PAGE_CACHE_SIZE) && (from == 0))
1929 SetPageUptodate(page);
1930
1931 /* might as well read a page, it is fast enough */
1932 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
1933 rc = cifs_readpage_worker(file, page, &offset);
1934 } else {
1935 /* should we try using another file handle if there is one -
1936 how would we lock it to prevent close of that handle
1937 racing with this read?
1938 In any case this will be written out by commit_write */
1939 }
1940 }
1941
1942 /* BB should we pass any errors back?
1943 e.g. if we do not have read access to the file */
1944 return 0;
1945}
1946
1947struct address_space_operations cifs_addr_ops = {
1948 .readpage = cifs_readpage,
1949 .readpages = cifs_readpages,
1950 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07001951 .writepages = cifs_writepages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 .prepare_write = cifs_prepare_write,
1953 .commit_write = cifs_commit_write,
1954 .set_page_dirty = __set_page_dirty_nobuffers,
1955 /* .sync_page = cifs_sync_page, */
1956 /* .direct_IO = */
1957};