blob: e9c1573f6aa73992542d1a99d77652e2c9bf6f69 [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;
Steve French55aa2e02006-05-30 18:09:31 +000087 else if ((flags & O_TRUNC) == O_TRUNC)
88 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 else
90 return FILE_OPEN;
91}
92
93/* all arguments to this function must be checked for validity in caller */
94static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
95 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
96 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
97 char *full_path, int xid)
98{
99 struct timespec temp;
100 int rc;
101
102 /* want handles we can use to read with first
103 in the list so we do not have to walk the
104 list to search for one in prepare_write */
105 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
106 list_add_tail(&pCifsFile->flist,
107 &pCifsInode->openFileList);
108 } else {
109 list_add(&pCifsFile->flist,
110 &pCifsInode->openFileList);
111 }
112 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 if (pCifsInode->clientCanCacheRead) {
114 /* we have the inode open somewhere else
115 no need to discard cache data */
116 goto client_can_cache;
117 }
118
119 /* BB need same check in cifs_create too? */
120 /* if not oplocked, invalidate inode pages if mtime or file
121 size changed */
122 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
123 if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
124 (file->f_dentry->d_inode->i_size ==
125 (loff_t)le64_to_cpu(buf->EndOfFile))) {
126 cFYI(1, ("inode unchanged on server"));
127 } else {
128 if (file->f_dentry->d_inode->i_mapping) {
129 /* BB no need to lock inode until after invalidate
130 since namei code should already have it locked? */
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800131 filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133 cFYI(1, ("invalidating remote inode since open detected it "
134 "changed"));
135 invalidate_remote_inode(file->f_dentry->d_inode);
136 }
137
138client_can_cache:
139 if (pTcon->ses->capabilities & CAP_UNIX)
140 rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
141 full_path, inode->i_sb, xid);
142 else
143 rc = cifs_get_inode_info(&file->f_dentry->d_inode,
144 full_path, buf, inode->i_sb, xid);
145
146 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
147 pCifsInode->clientCanCacheAll = TRUE;
148 pCifsInode->clientCanCacheRead = TRUE;
149 cFYI(1, ("Exclusive Oplock granted on inode %p",
150 file->f_dentry->d_inode));
151 } else if ((*oplock & 0xF) == OPLOCK_READ)
152 pCifsInode->clientCanCacheRead = TRUE;
153
154 return rc;
155}
156
157int cifs_open(struct inode *inode, struct file *file)
158{
159 int rc = -EACCES;
160 int xid, oplock;
161 struct cifs_sb_info *cifs_sb;
162 struct cifsTconInfo *pTcon;
163 struct cifsFileInfo *pCifsFile;
164 struct cifsInodeInfo *pCifsInode;
165 struct list_head *tmp;
166 char *full_path = NULL;
167 int desiredAccess;
168 int disposition;
169 __u16 netfid;
170 FILE_ALL_INFO *buf = NULL;
171
172 xid = GetXid();
173
174 cifs_sb = CIFS_SB(inode->i_sb);
175 pTcon = cifs_sb->tcon;
176
177 if (file->f_flags & O_CREAT) {
178 /* search inode for this file and fill in file->private_data */
179 pCifsInode = CIFS_I(file->f_dentry->d_inode);
180 read_lock(&GlobalSMBSeslock);
181 list_for_each(tmp, &pCifsInode->openFileList) {
182 pCifsFile = list_entry(tmp, struct cifsFileInfo,
183 flist);
184 if ((pCifsFile->pfile == NULL) &&
185 (pCifsFile->pid == current->tgid)) {
186 /* mode set in cifs_create */
187
188 /* needed for writepage */
189 pCifsFile->pfile = file;
190
191 file->private_data = pCifsFile;
192 break;
193 }
194 }
195 read_unlock(&GlobalSMBSeslock);
196 if (file->private_data != NULL) {
197 rc = 0;
198 FreeXid(xid);
199 return rc;
200 } else {
201 if (file->f_flags & O_EXCL)
202 cERROR(1, ("could not find file instance for "
Steve French26a21b92006-05-31 18:05:34 +0000203 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
205 }
206
Steve French7f573562005-08-30 11:32:14 -0700207 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (full_path == NULL) {
209 FreeXid(xid);
210 return -ENOMEM;
211 }
212
213 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
214 inode, file->f_flags, full_path));
215 desiredAccess = cifs_convert_flags(file->f_flags);
216
217/*********************************************************************
218 * open flag mapping table:
219 *
220 * POSIX Flag CIFS Disposition
221 * ---------- ----------------
222 * O_CREAT FILE_OPEN_IF
223 * O_CREAT | O_EXCL FILE_CREATE
224 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
225 * O_TRUNC FILE_OVERWRITE
226 * none of the above FILE_OPEN
227 *
228 * Note that there is not a direct match between disposition
229 * FILE_SUPERSEDE (ie create whether or not file exists although
230 * O_CREAT | O_TRUNC is similar but truncates the existing
231 * file rather than creating a new file as FILE_SUPERSEDE does
232 * (which uses the attributes / metadata passed in on open call)
233 *?
234 *? O_SYNC is a reasonable match to CIFS writethrough flag
235 *? and the read write flags match reasonably. O_LARGEFILE
236 *? is irrelevant because largefile support is always used
237 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
238 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
239 *********************************************************************/
240
241 disposition = cifs_get_disposition(file->f_flags);
242
243 if (oplockEnabled)
244 oplock = REQ_OPLOCK;
245 else
246 oplock = FALSE;
247
248 /* BB pass O_SYNC flag through on file attributes .. BB */
249
250 /* Also refresh inode by passing in file_info buf returned by SMBOpen
251 and calling get_inode_info with returned buf (at least helps
252 non-Unix server case) */
253
254 /* BB we can not do this if this is the second open of a file
255 and the first handle has writebehind data, we might be
256 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
257 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
258 if (!buf) {
259 rc = -ENOMEM;
260 goto out;
261 }
Steve French5bafd762006-06-07 00:18:43 +0000262
263 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
264 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
265 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700266 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
267 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000268 else
269 rc = -EIO; /* no NT SMB support fall into legacy open below */
270
Steve Frencha9d02ad2005-08-24 23:06:05 -0700271 if (rc == -EIO) {
272 /* Old server, try legacy style OpenX */
273 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
274 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
275 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
276 & CIFS_MOUNT_MAP_SPECIAL_CHR);
277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000279 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 goto out;
281 }
282 file->private_data =
283 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
284 if (file->private_data == NULL) {
285 rc = -ENOMEM;
286 goto out;
287 }
288 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 write_lock(&GlobalSMBSeslock);
290 list_add(&pCifsFile->tlist, &pTcon->openFileList);
291
292 pCifsInode = CIFS_I(file->f_dentry->d_inode);
293 if (pCifsInode) {
294 rc = cifs_open_inode_helper(inode, file, pCifsInode,
295 pCifsFile, pTcon,
296 &oplock, buf, full_path, xid);
297 } else {
298 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
301 if (oplock & CIFS_CREATE_ACTION) {
302 /* time to set mode which we can not set earlier due to
303 problems creating new read-only files */
304 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
305 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
306 inode->i_mode,
307 (__u64)-1, (__u64)-1, 0 /* dev */,
Steve French737b7582005-04-28 22:41:06 -0700308 cifs_sb->local_nls,
309 cifs_sb->mnt_cifs_flags &
310 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 } else {
312 /* BB implement via Windows security descriptors eg
313 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
314 -1, -1, local_nls);
315 in the meantime could set r/o dos attribute when
316 perms are eg: mode & 0222 == 0 */
317 }
318 }
319
320out:
321 kfree(buf);
322 kfree(full_path);
323 FreeXid(xid);
324 return rc;
325}
326
327/* Try to reaquire byte range locks that were released when session */
328/* to server was lost */
329static int cifs_relock_file(struct cifsFileInfo *cifsFile)
330{
331 int rc = 0;
332
333/* BB list all locks open on this file and relock */
334
335 return rc;
336}
337
338static int cifs_reopen_file(struct inode *inode, struct file *file,
339 int can_flush)
340{
341 int rc = -EACCES;
342 int xid, oplock;
343 struct cifs_sb_info *cifs_sb;
344 struct cifsTconInfo *pTcon;
345 struct cifsFileInfo *pCifsFile;
346 struct cifsInodeInfo *pCifsInode;
347 char *full_path = NULL;
348 int desiredAccess;
349 int disposition = FILE_OPEN;
350 __u16 netfid;
351
352 if (inode == NULL)
353 return -EBADF;
354 if (file->private_data) {
355 pCifsFile = (struct cifsFileInfo *)file->private_data;
356 } else
357 return -EBADF;
358
359 xid = GetXid();
360 down(&pCifsFile->fh_sem);
361 if (pCifsFile->invalidHandle == FALSE) {
362 up(&pCifsFile->fh_sem);
363 FreeXid(xid);
364 return 0;
365 }
366
367 if (file->f_dentry == NULL) {
368 up(&pCifsFile->fh_sem);
369 cFYI(1, ("failed file reopen, no valid name if dentry freed"));
370 FreeXid(xid);
371 return -EBADF;
372 }
373 cifs_sb = CIFS_SB(inode->i_sb);
374 pTcon = cifs_sb->tcon;
375/* can not grab rename sem here because various ops, including
376 those that already have the rename sem can end up causing writepage
377 to get called and if the server was down that means we end up here,
378 and we can never tell if the caller already has the rename_sem */
Steve French7f573562005-08-30 11:32:14 -0700379 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 if (full_path == NULL) {
381 up(&pCifsFile->fh_sem);
382 FreeXid(xid);
383 return -ENOMEM;
384 }
385
386 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
387 inode, file->f_flags,full_path));
388 desiredAccess = cifs_convert_flags(file->f_flags);
389
390 if (oplockEnabled)
391 oplock = REQ_OPLOCK;
392 else
393 oplock = FALSE;
394
395 /* Can not refresh inode by passing in file_info buf to be returned
396 by SMBOpen and then calling get_inode_info with returned buf
397 since file might have write behind data that needs to be flushed
398 and server version of file size can be stale. If we knew for sure
399 that inode was not dirty locally we could do this */
400
401/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
402 if (buf == 0) {
403 up(&pCifsFile->fh_sem);
404 kfree(full_path);
405 FreeXid(xid);
406 return -ENOMEM;
407 } */
408 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
409 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700410 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
411 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (rc) {
413 up(&pCifsFile->fh_sem);
Steve French26a21b92006-05-31 18:05:34 +0000414 cFYI(1, ("cifs_open returned 0x%x", rc));
415 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 } else {
417 pCifsFile->netfid = netfid;
418 pCifsFile->invalidHandle = FALSE;
419 up(&pCifsFile->fh_sem);
420 pCifsInode = CIFS_I(inode);
421 if (pCifsInode) {
422 if (can_flush) {
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800423 filemap_write_and_wait(inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 /* temporarily disable caching while we
425 go to server to get inode info */
426 pCifsInode->clientCanCacheAll = FALSE;
427 pCifsInode->clientCanCacheRead = FALSE;
428 if (pTcon->ses->capabilities & CAP_UNIX)
429 rc = cifs_get_inode_info_unix(&inode,
430 full_path, inode->i_sb, xid);
431 else
432 rc = cifs_get_inode_info(&inode,
433 full_path, NULL, inode->i_sb,
434 xid);
435 } /* else we are writing out data to server already
436 and could deadlock if we tried to flush data, and
437 since we do not know if we have data that would
438 invalidate the current end of file on the server
439 we can not go to the server to get the new inod
440 info */
441 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
442 pCifsInode->clientCanCacheAll = TRUE;
443 pCifsInode->clientCanCacheRead = TRUE;
444 cFYI(1, ("Exclusive Oplock granted on inode %p",
445 file->f_dentry->d_inode));
446 } else if ((oplock & 0xF) == OPLOCK_READ) {
447 pCifsInode->clientCanCacheRead = TRUE;
448 pCifsInode->clientCanCacheAll = FALSE;
449 } else {
450 pCifsInode->clientCanCacheRead = FALSE;
451 pCifsInode->clientCanCacheAll = FALSE;
452 }
453 cifs_relock_file(pCifsFile);
454 }
455 }
456
457 kfree(full_path);
458 FreeXid(xid);
459 return rc;
460}
461
462int cifs_close(struct inode *inode, struct file *file)
463{
464 int rc = 0;
465 int xid;
466 struct cifs_sb_info *cifs_sb;
467 struct cifsTconInfo *pTcon;
468 struct cifsFileInfo *pSMBFile =
469 (struct cifsFileInfo *)file->private_data;
470
471 xid = GetXid();
472
473 cifs_sb = CIFS_SB(inode->i_sb);
474 pTcon = cifs_sb->tcon;
475 if (pSMBFile) {
476 pSMBFile->closePend = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (pTcon) {
478 /* no sense reconnecting to close a file that is
479 already closed */
480 if (pTcon->tidStatus != CifsNeedReconnect) {
Steve French23e7dd72005-10-20 13:44:56 -0700481 int timeout = 2;
482 while((atomic_read(&pSMBFile->wrtPending) != 0)
483 && (timeout < 1000) ) {
484 /* Give write a better chance to get to
485 server ahead of the close. We do not
486 want to add a wait_q here as it would
487 increase the memory utilization as
488 the struct would be in each open file,
489 but this should give enough time to
490 clear the socket */
491 cERROR(1,("close with pending writes"));
492 msleep(timeout);
493 timeout *= 4;
494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 rc = CIFSSMBClose(xid, pTcon,
496 pSMBFile->netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498 }
Steve Frenchcbe04762005-04-28 22:41:05 -0700499 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 list_del(&pSMBFile->flist);
501 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700502 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 kfree(pSMBFile->search_resume_name);
504 kfree(file->private_data);
505 file->private_data = NULL;
506 } else
507 rc = -EBADF;
508
509 if (list_empty(&(CIFS_I(inode)->openFileList))) {
510 cFYI(1, ("closing last open instance for inode %p", inode));
511 /* if the file is not open we do not know if we can cache info
512 on this inode, much less write behind and read ahead */
513 CIFS_I(inode)->clientCanCacheRead = FALSE;
514 CIFS_I(inode)->clientCanCacheAll = FALSE;
515 }
516 if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
517 rc = CIFS_I(inode)->write_behind_rc;
518 FreeXid(xid);
519 return rc;
520}
521
522int cifs_closedir(struct inode *inode, struct file *file)
523{
524 int rc = 0;
525 int xid;
526 struct cifsFileInfo *pCFileStruct =
527 (struct cifsFileInfo *)file->private_data;
528 char *ptmp;
529
Steve French26a21b92006-05-31 18:05:34 +0000530 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 xid = GetXid();
533
534 if (pCFileStruct) {
535 struct cifsTconInfo *pTcon;
536 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
537
538 pTcon = cifs_sb->tcon;
539
540 cFYI(1, ("Freeing private data in close dir"));
Steve French31ca3bc2005-04-28 22:41:11 -0700541 if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
542 (pCFileStruct->invalidHandle == FALSE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 pCFileStruct->invalidHandle = TRUE;
544 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
545 cFYI(1, ("Closing uncompleted readdir with rc %d",
546 rc));
547 /* not much we can do if it fails anyway, ignore rc */
548 rc = 0;
549 }
550 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
551 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800552 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000554 if(pCFileStruct->srch_inf.smallBuf)
555 cifs_small_buf_release(ptmp);
556 else
557 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
559 ptmp = pCFileStruct->search_resume_name;
560 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800561 cFYI(1, ("closedir free resume name"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 pCFileStruct->search_resume_name = NULL;
563 kfree(ptmp);
564 }
565 kfree(file->private_data);
566 file->private_data = NULL;
567 }
568 /* BB can we lock the filestruct while this is going on? */
569 FreeXid(xid);
570 return rc;
571}
572
573int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
574{
575 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 __u32 numLock = 0;
577 __u32 numUnlock = 0;
578 __u64 length;
579 int wait_flag = FALSE;
580 struct cifs_sb_info *cifs_sb;
581 struct cifsTconInfo *pTcon;
Steve French08547b02006-02-28 22:39:25 +0000582 __u16 netfid;
583 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585 length = 1 + pfLock->fl_end - pfLock->fl_start;
586 rc = -EACCES;
587 xid = GetXid();
588
589 cFYI(1, ("Lock parm: 0x%x flockflags: "
590 "0x%x flocktype: 0x%x start: %lld end: %lld",
591 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
592 pfLock->fl_end));
593
594 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000595 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000597 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000599 cFYI(1, ("Blocking lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 wait_flag = TRUE;
601 }
602 if (pfLock->fl_flags & FL_ACCESS)
603 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000604 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 if (pfLock->fl_flags & FL_LEASE)
606 cFYI(1, ("Lease on file - not implemented yet"));
607 if (pfLock->fl_flags &
608 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
609 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
610
611 if (pfLock->fl_type == F_WRLCK) {
612 cFYI(1, ("F_WRLCK "));
613 numLock = 1;
614 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000615 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000617 /* Check if unlock includes more than
618 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000620 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 lockType |= LOCKING_ANDX_SHARED_LOCK;
622 numLock = 1;
623 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000624 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 numLock = 1;
626 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000627 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 lockType |= LOCKING_ANDX_SHARED_LOCK;
629 numLock = 1;
630 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000631 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
634 pTcon = cifs_sb->tcon;
635
636 if (file->private_data == NULL) {
637 FreeXid(xid);
638 return -EBADF;
639 }
Steve French08547b02006-02-28 22:39:25 +0000640 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Steve French08547b02006-02-28 22:39:25 +0000642
643 /* BB add code here to normalize offset and length to
644 account for negative length which we can not accept over the
645 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if (IS_GETLK(cmd)) {
Steve French08547b02006-02-28 22:39:25 +0000647 if(experimEnabled &&
Steve French82940a42006-03-02 03:24:57 +0000648 (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
649 (CIFS_UNIX_FCNTL_CAP &
650 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
Steve French08547b02006-02-28 22:39:25 +0000651 int posix_lock_type;
652 if(lockType & LOCKING_ANDX_SHARED_LOCK)
653 posix_lock_type = CIFS_RDLCK;
654 else
655 posix_lock_type = CIFS_WRLCK;
656 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000657 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000658 posix_lock_type, wait_flag);
659 FreeXid(xid);
660 return rc;
661 }
662
663 /* BB we could chain these into one lock request BB */
664 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
665 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if (rc == 0) {
Steve French08547b02006-02-28 22:39:25 +0000667 rc = CIFSSMBLock(xid, pTcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 pfLock->fl_start, 1 /* numUnlock */ ,
669 0 /* numLock */ , lockType,
670 0 /* wait flag */ );
671 pfLock->fl_type = F_UNLCK;
672 if (rc != 0)
673 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000674 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 rc = 0;
676
677 } else {
678 /* if rc == ERR_SHARING_VIOLATION ? */
679 rc = 0; /* do not change lock type to unlock
680 since range in use */
681 }
682
683 FreeXid(xid);
684 return rc;
685 }
Steve French08547b02006-02-28 22:39:25 +0000686 if (experimEnabled &&
Steve French82940a42006-03-02 03:24:57 +0000687 (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
688 (CIFS_UNIX_FCNTL_CAP &
689 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
Steve French08547b02006-02-28 22:39:25 +0000690 int posix_lock_type;
691 if(lockType & LOCKING_ANDX_SHARED_LOCK)
692 posix_lock_type = CIFS_RDLCK;
693 else
694 posix_lock_type = CIFS_WRLCK;
695
696 if(numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000697 posix_lock_type = CIFS_UNLCK;
Steve French08547b02006-02-28 22:39:25 +0000698 else if(numLock == 0) {
699 /* if no lock or unlock then nothing
700 to do since we do not know what it is */
701 FreeXid(xid);
702 return -EOPNOTSUPP;
703 }
704 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000705 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000706 posix_lock_type, wait_flag);
707 } else
708 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
709 numUnlock, numLock, lockType, wait_flag);
Steve Frenchd634cc12005-08-26 14:42:59 -0500710 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 posix_lock_file_wait(file, pfLock);
712 FreeXid(xid);
713 return rc;
714}
715
716ssize_t cifs_user_write(struct file *file, const char __user *write_data,
717 size_t write_size, loff_t *poffset)
718{
719 int rc = 0;
720 unsigned int bytes_written = 0;
721 unsigned int total_written;
722 struct cifs_sb_info *cifs_sb;
723 struct cifsTconInfo *pTcon;
724 int xid, long_op;
725 struct cifsFileInfo *open_file;
726
727 if (file->f_dentry == NULL)
728 return -EBADF;
729
730 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
731 if (cifs_sb == NULL)
732 return -EBADF;
733
734 pTcon = cifs_sb->tcon;
735
736 /* cFYI(1,
737 (" write %d bytes to offset %lld of %s", write_size,
738 *poffset, file->f_dentry->d_name.name)); */
739
740 if (file->private_data == NULL)
741 return -EBADF;
742 else
743 open_file = (struct cifsFileInfo *) file->private_data;
744
745 xid = GetXid();
746 if (file->f_dentry->d_inode == NULL) {
747 FreeXid(xid);
748 return -EBADF;
749 }
750
751 if (*poffset > file->f_dentry->d_inode->i_size)
752 long_op = 2; /* writes past end of file can take a long time */
753 else
754 long_op = 1;
755
756 for (total_written = 0; write_size > total_written;
757 total_written += bytes_written) {
758 rc = -EAGAIN;
759 while (rc == -EAGAIN) {
760 if (file->private_data == NULL) {
761 /* file has been closed on us */
762 FreeXid(xid);
763 /* if we have gotten here we have written some data
764 and blocked, and the file has been freed on us while
765 we blocked so return what we managed to write */
766 return total_written;
767 }
768 if (open_file->closePend) {
769 FreeXid(xid);
770 if (total_written)
771 return total_written;
772 else
773 return -EBADF;
774 }
775 if (open_file->invalidHandle) {
776 if ((file->f_dentry == NULL) ||
777 (file->f_dentry->d_inode == NULL)) {
778 FreeXid(xid);
779 return total_written;
780 }
781 /* we could deadlock if we called
782 filemap_fdatawait from here so tell
783 reopen_file not to flush data to server
784 now */
785 rc = cifs_reopen_file(file->f_dentry->d_inode,
786 file, FALSE);
787 if (rc != 0)
788 break;
789 }
790
791 rc = CIFSSMBWrite(xid, pTcon,
792 open_file->netfid,
793 min_t(const int, cifs_sb->wsize,
794 write_size - total_written),
795 *poffset, &bytes_written,
796 NULL, write_data + total_written, long_op);
797 }
798 if (rc || (bytes_written == 0)) {
799 if (total_written)
800 break;
801 else {
802 FreeXid(xid);
803 return rc;
804 }
805 } else
806 *poffset += bytes_written;
807 long_op = FALSE; /* subsequent writes fast -
808 15 seconds is plenty */
809 }
810
Steve Frencha4544342005-08-24 13:59:35 -0700811 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* since the write may have blocked check these pointers again */
814 if (file->f_dentry) {
815 if (file->f_dentry->d_inode) {
816 struct inode *inode = file->f_dentry->d_inode;
817 inode->i_ctime = inode->i_mtime =
818 current_fs_time(inode->i_sb);
819 if (total_written > 0) {
820 if (*poffset > file->f_dentry->d_inode->i_size)
821 i_size_write(file->f_dentry->d_inode,
822 *poffset);
823 }
824 mark_inode_dirty_sync(file->f_dentry->d_inode);
825 }
826 }
827 FreeXid(xid);
828 return total_written;
829}
830
831static ssize_t cifs_write(struct file *file, const char *write_data,
832 size_t write_size, loff_t *poffset)
833{
834 int rc = 0;
835 unsigned int bytes_written = 0;
836 unsigned int total_written;
837 struct cifs_sb_info *cifs_sb;
838 struct cifsTconInfo *pTcon;
839 int xid, long_op;
840 struct cifsFileInfo *open_file;
841
842 if (file->f_dentry == NULL)
843 return -EBADF;
844
845 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
846 if (cifs_sb == NULL)
847 return -EBADF;
848
849 pTcon = cifs_sb->tcon;
850
Steve Frenchab2f2182005-09-15 20:44:50 -0700851 cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
852 *poffset, file->f_dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 if (file->private_data == NULL)
855 return -EBADF;
856 else
857 open_file = (struct cifsFileInfo *)file->private_data;
858
859 xid = GetXid();
860 if (file->f_dentry->d_inode == NULL) {
861 FreeXid(xid);
862 return -EBADF;
863 }
864
865 if (*poffset > file->f_dentry->d_inode->i_size)
866 long_op = 2; /* writes past end of file can take a long time */
867 else
868 long_op = 1;
869
870 for (total_written = 0; write_size > total_written;
871 total_written += bytes_written) {
872 rc = -EAGAIN;
873 while (rc == -EAGAIN) {
874 if (file->private_data == NULL) {
875 /* file has been closed on us */
876 FreeXid(xid);
877 /* if we have gotten here we have written some data
878 and blocked, and the file has been freed on us
879 while we blocked so return what we managed to
880 write */
881 return total_written;
882 }
883 if (open_file->closePend) {
884 FreeXid(xid);
885 if (total_written)
886 return total_written;
887 else
888 return -EBADF;
889 }
890 if (open_file->invalidHandle) {
891 if ((file->f_dentry == NULL) ||
892 (file->f_dentry->d_inode == NULL)) {
893 FreeXid(xid);
894 return total_written;
895 }
896 /* we could deadlock if we called
897 filemap_fdatawait from here so tell
898 reopen_file not to flush data to
899 server now */
900 rc = cifs_reopen_file(file->f_dentry->d_inode,
901 file, FALSE);
902 if (rc != 0)
903 break;
904 }
Steve Frenchc01f36a2006-05-30 18:05:10 +0000905 if(experimEnabled || (pTcon->ses->server &&
Steve French08775832006-05-30 18:08:26 +0000906 ((pTcon->ses->server->secMode &
907 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +0000908 == 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;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001078 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001079 pgoff_t index;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001080 int range_whole = 0;
Steve French37c0eb42005-10-05 14:50:29 -07001081 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);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001121 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001122 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001123 end = -1;
1124 } else {
1125 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1126 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1127 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1128 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001129 scanned = 1;
1130 }
1131retry:
1132 while (!done && (index <= end) &&
1133 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1134 PAGECACHE_TAG_DIRTY,
1135 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1136 int first;
1137 unsigned int i;
1138
Steve French37c0eb42005-10-05 14:50:29 -07001139 first = -1;
1140 next = 0;
1141 n_iov = 0;
1142 bytes_to_write = 0;
1143
1144 for (i = 0; i < nr_pages; i++) {
1145 page = pvec.pages[i];
1146 /*
1147 * At this point we hold neither mapping->tree_lock nor
1148 * lock on the page itself: the page may be truncated or
1149 * invalidated (changing page->mapping to NULL), or even
1150 * swizzled back from swapper_space to tmpfs file
1151 * mapping
1152 */
1153
1154 if (first < 0)
1155 lock_page(page);
1156 else if (TestSetPageLocked(page))
1157 break;
1158
1159 if (unlikely(page->mapping != mapping)) {
1160 unlock_page(page);
1161 break;
1162 }
1163
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001164 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001165 done = 1;
1166 unlock_page(page);
1167 break;
1168 }
1169
1170 if (next && (page->index != next)) {
1171 /* Not next consecutive page */
1172 unlock_page(page);
1173 break;
1174 }
1175
1176 if (wbc->sync_mode != WB_SYNC_NONE)
1177 wait_on_page_writeback(page);
1178
1179 if (PageWriteback(page) ||
1180 !test_clear_page_dirty(page)) {
1181 unlock_page(page);
1182 break;
1183 }
Steve French84d2f072005-10-12 15:32:05 -07001184
1185 if (page_offset(page) >= mapping->host->i_size) {
1186 done = 1;
1187 unlock_page(page);
1188 break;
1189 }
1190
Steve French37c0eb42005-10-05 14:50:29 -07001191 /*
1192 * BB can we get rid of this? pages are held by pvec
1193 */
1194 page_cache_get(page);
1195
Steve French84d2f072005-10-12 15:32:05 -07001196 len = min(mapping->host->i_size - page_offset(page),
1197 (loff_t)PAGE_CACHE_SIZE);
1198
Steve French37c0eb42005-10-05 14:50:29 -07001199 /* reserve iov[0] for the smb header */
1200 n_iov++;
1201 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001202 iov[n_iov].iov_len = len;
1203 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001204
1205 if (first < 0) {
1206 first = i;
1207 offset = page_offset(page);
1208 }
1209 next = page->index + 1;
1210 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1211 break;
1212 }
1213 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001214 /* Search for a writable handle every time we call
1215 * CIFSSMBWrite2. We can't rely on the last handle
1216 * we used to still be valid
1217 */
1218 open_file = find_writable_file(CIFS_I(mapping->host));
1219 if (!open_file) {
1220 cERROR(1, ("No writable handles for inode"));
1221 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001222 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001223 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1224 open_file->netfid,
1225 bytes_to_write, offset,
1226 &bytes_written, iov, n_iov,
1227 1);
1228 atomic_dec(&open_file->wrtPending);
1229 if (rc || bytes_written < bytes_to_write) {
1230 cERROR(1,("Write2 ret %d, written = %d",
1231 rc, bytes_written));
1232 /* BB what if continued retry is
1233 requested via mount flags? */
1234 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001235 } else {
1236 cifs_stats_bytes_written(cifs_sb->tcon,
1237 bytes_written);
1238 }
Steve French37c0eb42005-10-05 14:50:29 -07001239 }
1240 for (i = 0; i < n_iov; i++) {
1241 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001242 /* Should we also set page error on
1243 success rc but too little data written? */
1244 /* BB investigate retry logic on temporary
1245 server crash cases and how recovery works
1246 when page marked as error */
1247 if(rc)
1248 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001249 kunmap(page);
1250 unlock_page(page);
1251 page_cache_release(page);
1252 }
1253 if ((wbc->nr_to_write -= n_iov) <= 0)
1254 done = 1;
1255 index = next;
1256 }
1257 pagevec_release(&pvec);
1258 }
1259 if (!scanned && !done) {
1260 /*
1261 * We hit the last page and there is more work to be done: wrap
1262 * back to the start of the file
1263 */
1264 scanned = 1;
1265 index = 0;
1266 goto retry;
1267 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001268 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001269 mapping->writeback_index = index;
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 FreeXid(xid);
Steve French37c0eb42005-10-05 14:50:29 -07001272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 return rc;
1274}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
1276static int cifs_writepage(struct page* page, struct writeback_control *wbc)
1277{
1278 int rc = -EFAULT;
1279 int xid;
1280
1281 xid = GetXid();
1282/* BB add check for wbc flags */
1283 page_cache_get(page);
1284 if (!PageUptodate(page)) {
1285 cFYI(1, ("ppw - page not up to date"));
1286 }
1287
1288 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1289 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1290 unlock_page(page);
1291 page_cache_release(page);
1292 FreeXid(xid);
1293 return rc;
1294}
1295
1296static int cifs_commit_write(struct file *file, struct page *page,
1297 unsigned offset, unsigned to)
1298{
1299 int xid;
1300 int rc = 0;
1301 struct inode *inode = page->mapping->host;
1302 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1303 char *page_data;
1304
1305 xid = GetXid();
1306 cFYI(1, ("commit write for page %p up to position %lld for %d",
1307 page, position, to));
1308 if (position > inode->i_size) {
1309 i_size_write(inode, position);
1310 /* if (file->private_data == NULL) {
1311 rc = -EBADF;
1312 } else {
1313 open_file = (struct cifsFileInfo *)file->private_data;
1314 cifs_sb = CIFS_SB(inode->i_sb);
1315 rc = -EAGAIN;
1316 while (rc == -EAGAIN) {
1317 if ((open_file->invalidHandle) &&
1318 (!open_file->closePend)) {
1319 rc = cifs_reopen_file(
1320 file->f_dentry->d_inode, file);
1321 if (rc != 0)
1322 break;
1323 }
1324 if (!open_file->closePend) {
1325 rc = CIFSSMBSetFileSize(xid,
1326 cifs_sb->tcon, position,
1327 open_file->netfid,
1328 open_file->pid, FALSE);
1329 } else {
1330 rc = -EBADF;
1331 break;
1332 }
1333 }
1334 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1335 } */
1336 }
1337 if (!PageUptodate(page)) {
1338 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1339 /* can not rely on (or let) writepage write this data */
1340 if (to < offset) {
1341 cFYI(1, ("Illegal offsets, can not copy from %d to %d",
1342 offset, to));
1343 FreeXid(xid);
1344 return rc;
1345 }
1346 /* this is probably better than directly calling
1347 partialpage_write since in this function the file handle is
1348 known which we might as well leverage */
1349 /* BB check if anything else missing out of ppw
1350 such as updating last write time */
1351 page_data = kmap(page);
1352 rc = cifs_write(file, page_data + offset, to-offset,
1353 &position);
1354 if (rc > 0)
1355 rc = 0;
1356 /* else if (rc < 0) should we set writebehind rc? */
1357 kunmap(page);
1358 } else {
1359 set_page_dirty(page);
1360 }
1361
1362 FreeXid(xid);
1363 return rc;
1364}
1365
1366int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1367{
1368 int xid;
1369 int rc = 0;
1370 struct inode *inode = file->f_dentry->d_inode;
1371
1372 xid = GetXid();
1373
Steve French26a21b92006-05-31 18:05:34 +00001374 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 dentry->d_name.name, datasync));
1376
1377 rc = filemap_fdatawrite(inode->i_mapping);
1378 if (rc == 0)
1379 CIFS_I(inode)->write_behind_rc = 0;
1380 FreeXid(xid);
1381 return rc;
1382}
1383
NeilBrown3978d7172006-03-26 01:37:17 -08001384/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385{
1386 struct address_space *mapping;
1387 struct inode *inode;
1388 unsigned long index = page->index;
1389 unsigned int rpages = 0;
1390 int rc = 0;
1391
1392 cFYI(1, ("sync page %p",page));
1393 mapping = page->mapping;
1394 if (!mapping)
1395 return 0;
1396 inode = mapping->host;
1397 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001398 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
1400/* fill in rpages then
1401 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1402
Steve French26a21b92006-05-31 18:05:34 +00001403/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
NeilBrown3978d7172006-03-26 01:37:17 -08001405#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (rc < 0)
1407 return rc;
1408 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001409#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410} */
1411
1412/*
1413 * As file closes, flush all cached write data for this inode checking
1414 * for write behind errors.
1415 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001416int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417{
1418 struct inode * inode = file->f_dentry->d_inode;
1419 int rc = 0;
1420
1421 /* Rather than do the steps manually:
1422 lock the inode for writing
1423 loop through pages looking for write behind data (dirty pages)
1424 coalesce into contiguous 16K (or smaller) chunks to write to server
1425 send to server (prefer in parallel)
1426 deal with writebehind errors
1427 unlock inode for writing
1428 filemapfdatawrite appears easier for the time being */
1429
1430 rc = filemap_fdatawrite(inode->i_mapping);
1431 if (!rc) /* reset wb rc if we were able to write out dirty pages */
1432 CIFS_I(inode)->write_behind_rc = 0;
1433
1434 cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
1435
1436 return rc;
1437}
1438
1439ssize_t cifs_user_read(struct file *file, char __user *read_data,
1440 size_t read_size, loff_t *poffset)
1441{
1442 int rc = -EACCES;
1443 unsigned int bytes_read = 0;
1444 unsigned int total_read = 0;
1445 unsigned int current_read_size;
1446 struct cifs_sb_info *cifs_sb;
1447 struct cifsTconInfo *pTcon;
1448 int xid;
1449 struct cifsFileInfo *open_file;
1450 char *smb_read_data;
1451 char __user *current_offset;
1452 struct smb_com_read_rsp *pSMBr;
1453
1454 xid = GetXid();
1455 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1456 pTcon = cifs_sb->tcon;
1457
1458 if (file->private_data == NULL) {
1459 FreeXid(xid);
1460 return -EBADF;
1461 }
1462 open_file = (struct cifsFileInfo *)file->private_data;
1463
1464 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1465 cFYI(1, ("attempting read on write only file instance"));
1466 }
1467 for (total_read = 0, current_offset = read_data;
1468 read_size > total_read;
1469 total_read += bytes_read, current_offset += bytes_read) {
1470 current_read_size = min_t(const int, read_size - total_read,
1471 cifs_sb->rsize);
1472 rc = -EAGAIN;
1473 smb_read_data = NULL;
1474 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001475 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if ((open_file->invalidHandle) &&
1477 (!open_file->closePend)) {
1478 rc = cifs_reopen_file(file->f_dentry->d_inode,
1479 file, TRUE);
1480 if (rc != 0)
1481 break;
1482 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001483 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001484 open_file->netfid,
1485 current_read_size, *poffset,
1486 &bytes_read, &smb_read_data,
1487 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001490 if (copy_to_user(current_offset,
1491 smb_read_data +
1492 4 /* RFC1001 length field */ +
1493 le16_to_cpu(pSMBr->DataOffset),
1494 bytes_read)) {
1495 rc = -EFAULT;
1496 }
1497
Steve Frenchec637e32005-12-12 20:53:18 -08001498 if(buf_type == CIFS_SMALL_BUFFER)
1499 cifs_small_buf_release(smb_read_data);
1500 else if(buf_type == CIFS_LARGE_BUFFER)
1501 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 smb_read_data = NULL;
1503 }
1504 }
1505 if (rc || (bytes_read == 0)) {
1506 if (total_read) {
1507 break;
1508 } else {
1509 FreeXid(xid);
1510 return rc;
1511 }
1512 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001513 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 *poffset += bytes_read;
1515 }
1516 }
1517 FreeXid(xid);
1518 return total_read;
1519}
1520
1521
1522static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1523 loff_t *poffset)
1524{
1525 int rc = -EACCES;
1526 unsigned int bytes_read = 0;
1527 unsigned int total_read;
1528 unsigned int current_read_size;
1529 struct cifs_sb_info *cifs_sb;
1530 struct cifsTconInfo *pTcon;
1531 int xid;
1532 char *current_offset;
1533 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001534 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536 xid = GetXid();
1537 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1538 pTcon = cifs_sb->tcon;
1539
1540 if (file->private_data == NULL) {
1541 FreeXid(xid);
1542 return -EBADF;
1543 }
1544 open_file = (struct cifsFileInfo *)file->private_data;
1545
1546 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1547 cFYI(1, ("attempting read on write only file instance"));
1548
1549 for (total_read = 0, current_offset = read_data;
1550 read_size > total_read;
1551 total_read += bytes_read, current_offset += bytes_read) {
1552 current_read_size = min_t(const int, read_size - total_read,
1553 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001554 /* For windows me and 9x we do not want to request more
1555 than it negotiated since it will refuse the read then */
1556 if((pTcon->ses) &&
1557 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1558 current_read_size = min_t(const int, current_read_size,
1559 pTcon->ses->server->maxBuf - 128);
1560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 rc = -EAGAIN;
1562 while (rc == -EAGAIN) {
1563 if ((open_file->invalidHandle) &&
1564 (!open_file->closePend)) {
1565 rc = cifs_reopen_file(file->f_dentry->d_inode,
1566 file, TRUE);
1567 if (rc != 0)
1568 break;
1569 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001570 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001571 open_file->netfid,
1572 current_read_size, *poffset,
1573 &bytes_read, &current_offset,
1574 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
1576 if (rc || (bytes_read == 0)) {
1577 if (total_read) {
1578 break;
1579 } else {
1580 FreeXid(xid);
1581 return rc;
1582 }
1583 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001584 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 *poffset += bytes_read;
1586 }
1587 }
1588 FreeXid(xid);
1589 return total_read;
1590}
1591
1592int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1593{
1594 struct dentry *dentry = file->f_dentry;
1595 int rc, xid;
1596
1597 xid = GetXid();
1598 rc = cifs_revalidate(dentry);
1599 if (rc) {
1600 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1601 FreeXid(xid);
1602 return rc;
1603 }
1604 rc = generic_file_mmap(file, vma);
1605 FreeXid(xid);
1606 return rc;
1607}
1608
1609
1610static void cifs_copy_cache_pages(struct address_space *mapping,
1611 struct list_head *pages, int bytes_read, char *data,
1612 struct pagevec *plru_pvec)
1613{
1614 struct page *page;
1615 char *target;
1616
1617 while (bytes_read > 0) {
1618 if (list_empty(pages))
1619 break;
1620
1621 page = list_entry(pages->prev, struct page, lru);
1622 list_del(&page->lru);
1623
1624 if (add_to_page_cache(page, mapping, page->index,
1625 GFP_KERNEL)) {
1626 page_cache_release(page);
1627 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001628 data += PAGE_CACHE_SIZE;
1629 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 continue;
1631 }
1632
1633 target = kmap_atomic(page,KM_USER0);
1634
1635 if (PAGE_CACHE_SIZE > bytes_read) {
1636 memcpy(target, data, bytes_read);
1637 /* zero the tail end of this partial page */
1638 memset(target + bytes_read, 0,
1639 PAGE_CACHE_SIZE - bytes_read);
1640 bytes_read = 0;
1641 } else {
1642 memcpy(target, data, PAGE_CACHE_SIZE);
1643 bytes_read -= PAGE_CACHE_SIZE;
1644 }
1645 kunmap_atomic(target, KM_USER0);
1646
1647 flush_dcache_page(page);
1648 SetPageUptodate(page);
1649 unlock_page(page);
1650 if (!pagevec_add(plru_pvec, page))
1651 __pagevec_lru_add(plru_pvec);
1652 data += PAGE_CACHE_SIZE;
1653 }
1654 return;
1655}
1656
1657static int cifs_readpages(struct file *file, struct address_space *mapping,
1658 struct list_head *page_list, unsigned num_pages)
1659{
1660 int rc = -EACCES;
1661 int xid;
1662 loff_t offset;
1663 struct page *page;
1664 struct cifs_sb_info *cifs_sb;
1665 struct cifsTconInfo *pTcon;
1666 int bytes_read = 0;
1667 unsigned int read_size,i;
1668 char *smb_read_data = NULL;
1669 struct smb_com_read_rsp *pSMBr;
1670 struct pagevec lru_pvec;
1671 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 xid = GetXid();
1675 if (file->private_data == NULL) {
1676 FreeXid(xid);
1677 return -EBADF;
1678 }
1679 open_file = (struct cifsFileInfo *)file->private_data;
1680 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1681 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 pagevec_init(&lru_pvec, 0);
1684
1685 for (i = 0; i < num_pages; ) {
1686 unsigned contig_pages;
1687 struct page *tmp_page;
1688 unsigned long expected_index;
1689
1690 if (list_empty(page_list))
1691 break;
1692
1693 page = list_entry(page_list->prev, struct page, lru);
1694 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1695
1696 /* count adjacent pages that we will read into */
1697 contig_pages = 0;
1698 expected_index =
1699 list_entry(page_list->prev, struct page, lru)->index;
1700 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1701 if (tmp_page->index == expected_index) {
1702 contig_pages++;
1703 expected_index++;
1704 } else
1705 break;
1706 }
1707 if (contig_pages + i > num_pages)
1708 contig_pages = num_pages - i;
1709
1710 /* for reads over a certain size could initiate async
1711 read ahead */
1712
1713 read_size = contig_pages * PAGE_CACHE_SIZE;
1714 /* Read size needs to be in multiples of one page */
1715 read_size = min_t(const unsigned int, read_size,
1716 cifs_sb->rsize & PAGE_CACHE_MASK);
1717
1718 rc = -EAGAIN;
1719 while (rc == -EAGAIN) {
1720 if ((open_file->invalidHandle) &&
1721 (!open_file->closePend)) {
1722 rc = cifs_reopen_file(file->f_dentry->d_inode,
1723 file, TRUE);
1724 if (rc != 0)
1725 break;
1726 }
1727
Steve Frenchbfa0d752005-08-31 21:50:37 -07001728 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001729 open_file->netfid,
1730 read_size, offset,
1731 &bytes_read, &smb_read_data,
1732 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001733 /* BB more RC checks ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (rc== -EAGAIN) {
1735 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001736 if(buf_type == CIFS_SMALL_BUFFER)
1737 cifs_small_buf_release(smb_read_data);
1738 else if(buf_type == CIFS_LARGE_BUFFER)
1739 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 smb_read_data = NULL;
1741 }
1742 }
1743 }
1744 if ((rc < 0) || (smb_read_data == NULL)) {
1745 cFYI(1, ("Read error in readpages: %d", rc));
1746 /* clean up remaing pages off list */
1747 while (!list_empty(page_list) && (i < num_pages)) {
1748 page = list_entry(page_list->prev, struct page,
1749 lru);
1750 list_del(&page->lru);
1751 page_cache_release(page);
1752 }
1753 break;
1754 } else if (bytes_read > 0) {
1755 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1756 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1757 smb_read_data + 4 /* RFC1001 hdr */ +
1758 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1759
1760 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001761 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1763 i++; /* account for partial page */
1764
1765 /* server copy of file can have smaller size
1766 than client */
1767 /* BB do we need to verify this common case ?
1768 this case is ok - if we are at server EOF
1769 we will hit it on next read */
1770
1771 /* while (!list_empty(page_list) && (i < num_pages)) {
1772 page = list_entry(page_list->prev,
1773 struct page, list);
1774 list_del(&page->list);
1775 page_cache_release(page);
1776 }
1777 break; */
1778 }
1779 } else {
1780 cFYI(1, ("No bytes read (%d) at offset %lld . "
1781 "Cleaning remaining pages from readahead list",
1782 bytes_read, offset));
1783 /* BB turn off caching and do new lookup on
1784 file size at server? */
1785 while (!list_empty(page_list) && (i < num_pages)) {
1786 page = list_entry(page_list->prev, struct page,
1787 lru);
1788 list_del(&page->lru);
1789
1790 /* BB removeme - replace with zero of page? */
1791 page_cache_release(page);
1792 }
1793 break;
1794 }
1795 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001796 if(buf_type == CIFS_SMALL_BUFFER)
1797 cifs_small_buf_release(smb_read_data);
1798 else if(buf_type == CIFS_LARGE_BUFFER)
1799 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 smb_read_data = NULL;
1801 }
1802 bytes_read = 0;
1803 }
1804
1805 pagevec_lru_add(&lru_pvec);
1806
1807/* need to free smb_read_data buf before exit */
1808 if (smb_read_data) {
Steve French47c886b2006-01-18 14:20:39 -08001809 if(buf_type == CIFS_SMALL_BUFFER)
1810 cifs_small_buf_release(smb_read_data);
1811 else if(buf_type == CIFS_LARGE_BUFFER)
1812 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 smb_read_data = NULL;
1814 }
1815
1816 FreeXid(xid);
1817 return rc;
1818}
1819
1820static int cifs_readpage_worker(struct file *file, struct page *page,
1821 loff_t *poffset)
1822{
1823 char *read_data;
1824 int rc;
1825
1826 page_cache_get(page);
1827 read_data = kmap(page);
1828 /* for reads over a certain size could initiate async read ahead */
1829
1830 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1831
1832 if (rc < 0)
1833 goto io_error;
1834 else
Steve French26a21b92006-05-31 18:05:34 +00001835 cFYI(1, ("Bytes read %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 file->f_dentry->d_inode->i_atime =
1838 current_fs_time(file->f_dentry->d_inode->i_sb);
1839
1840 if (PAGE_CACHE_SIZE > rc)
1841 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1842
1843 flush_dcache_page(page);
1844 SetPageUptodate(page);
1845 rc = 0;
1846
1847io_error:
1848 kunmap(page);
1849 page_cache_release(page);
1850 return rc;
1851}
1852
1853static int cifs_readpage(struct file *file, struct page *page)
1854{
1855 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1856 int rc = -EACCES;
1857 int xid;
1858
1859 xid = GetXid();
1860
1861 if (file->private_data == NULL) {
1862 FreeXid(xid);
1863 return -EBADF;
1864 }
1865
1866 cFYI(1, ("readpage %p at offset %d 0x%x\n",
1867 page, (int)offset, (int)offset));
1868
1869 rc = cifs_readpage_worker(file, page, &offset);
1870
1871 unlock_page(page);
1872
1873 FreeXid(xid);
1874 return rc;
1875}
1876
1877/* We do not want to update the file size from server for inodes
1878 open for write - to avoid races with writepage extending
1879 the file - in the future we could consider allowing
1880 refreshing the inode only on increases in the file size
1881 but this is tricky to do without racing with writebehind
1882 page caching in the current Linux kernel design */
1883int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1884{
Steve French23e7dd72005-10-20 13:44:56 -07001885 struct cifsFileInfo *open_file = NULL;
1886
1887 if (cifsInode)
1888 open_file = find_writable_file(cifsInode);
1889
1890 if(open_file) {
Steve Frenchc32a0b62006-01-12 14:41:28 -08001891 struct cifs_sb_info *cifs_sb;
1892
Steve French23e7dd72005-10-20 13:44:56 -07001893 /* there is not actually a write pending so let
1894 this handle go free and allow it to
1895 be closable if needed */
1896 atomic_dec(&open_file->wrtPending);
Steve Frenchc32a0b62006-01-12 14:41:28 -08001897
1898 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
1899 if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
1900 /* since no page cache to corrupt on directio
1901 we can change size safely */
1902 return 1;
1903 }
1904
Steve French6148a742005-10-05 12:23:19 -07001905 return 0;
Steve French23e7dd72005-10-20 13:44:56 -07001906 } else
Steve French6148a742005-10-05 12:23:19 -07001907 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908}
1909
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910static int cifs_prepare_write(struct file *file, struct page *page,
1911 unsigned from, unsigned to)
1912{
1913 int rc = 0;
1914 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1915 cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
1916 if (!PageUptodate(page)) {
1917 /* if (to - from != PAGE_CACHE_SIZE) {
1918 void *kaddr = kmap_atomic(page, KM_USER0);
1919 memset(kaddr, 0, from);
1920 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1921 flush_dcache_page(page);
1922 kunmap_atomic(kaddr, KM_USER0);
1923 } */
1924 /* If we are writing a full page it will be up to date,
1925 no need to read from the server */
1926 if ((to == PAGE_CACHE_SIZE) && (from == 0))
1927 SetPageUptodate(page);
1928
1929 /* might as well read a page, it is fast enough */
1930 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
1931 rc = cifs_readpage_worker(file, page, &offset);
1932 } else {
1933 /* should we try using another file handle if there is one -
1934 how would we lock it to prevent close of that handle
1935 racing with this read?
1936 In any case this will be written out by commit_write */
1937 }
1938 }
1939
1940 /* BB should we pass any errors back?
1941 e.g. if we do not have read access to the file */
1942 return 0;
1943}
1944
1945struct address_space_operations cifs_addr_ops = {
1946 .readpage = cifs_readpage,
1947 .readpages = cifs_readpages,
1948 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07001949 .writepages = cifs_writepages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 .prepare_write = cifs_prepare_write,
1951 .commit_write = cifs_commit_write,
1952 .set_page_dirty = __set_page_dirty_nobuffers,
1953 /* .sync_page = cifs_sync_page, */
1954 /* .direct_IO = */
1955};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00001956
1957/*
1958 * cifs_readpages requires the server to support a buffer large enough to
1959 * contain the header plus one complete page of data. Otherwise, we need
1960 * to leave cifs_readpages out of the address space operations.
1961 */
1962struct address_space_operations cifs_addr_ops_smallbuf = {
1963 .readpage = cifs_readpage,
1964 .writepage = cifs_writepage,
1965 .writepages = cifs_writepages,
1966 .prepare_write = cifs_prepare_write,
1967 .commit_write = cifs_commit_write,
1968 .set_page_dirty = __set_page_dirty_nobuffers,
1969 /* .sync_page = cifs_sync_page, */
1970 /* .direct_IO = */
1971};