blob: 39b23f4fa6c323232c162b94a2b92e3b6a399993 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/div64.h>
33#include "cifsfs.h"
34#include "cifspdu.h"
35#include "cifsglob.h"
36#include "cifsproto.h"
37#include "cifs_unicode.h"
38#include "cifs_debug.h"
39#include "cifs_fs_sb.h"
40
41static inline struct cifsFileInfo *cifs_init_private(
42 struct cifsFileInfo *private_data, struct inode *inode,
43 struct file *file, __u16 netfid)
44{
45 memset(private_data, 0, sizeof(struct cifsFileInfo));
46 private_data->netfid = netfid;
47 private_data->pid = current->tgid;
48 init_MUTEX(&private_data->fh_sem);
49 private_data->pfile = file; /* needed for writepage */
50 private_data->pInode = inode;
51 private_data->invalidHandle = FALSE;
52 private_data->closePend = FALSE;
53
54 return private_data;
55}
56
57static inline int cifs_convert_flags(unsigned int flags)
58{
59 if ((flags & O_ACCMODE) == O_RDONLY)
60 return GENERIC_READ;
61 else if ((flags & O_ACCMODE) == O_WRONLY)
62 return GENERIC_WRITE;
63 else if ((flags & O_ACCMODE) == O_RDWR) {
64 /* GENERIC_ALL is too much permission to request
65 can cause unnecessary access denied on create */
66 /* return GENERIC_ALL; */
67 return (GENERIC_READ | GENERIC_WRITE);
68 }
69
70 return 0x20197;
71}
72
73static inline int cifs_get_disposition(unsigned int flags)
74{
75 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
76 return FILE_CREATE;
77 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
78 return FILE_OVERWRITE_IF;
79 else if ((flags & O_CREAT) == O_CREAT)
80 return FILE_OPEN_IF;
81 else
82 return FILE_OPEN;
83}
84
85/* all arguments to this function must be checked for validity in caller */
86static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
87 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
88 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
89 char *full_path, int xid)
90{
91 struct timespec temp;
92 int rc;
93
94 /* want handles we can use to read with first
95 in the list so we do not have to walk the
96 list to search for one in prepare_write */
97 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
98 list_add_tail(&pCifsFile->flist,
99 &pCifsInode->openFileList);
100 } else {
101 list_add(&pCifsFile->flist,
102 &pCifsInode->openFileList);
103 }
104 write_unlock(&GlobalSMBSeslock);
105 write_unlock(&file->f_owner.lock);
106 if (pCifsInode->clientCanCacheRead) {
107 /* we have the inode open somewhere else
108 no need to discard cache data */
109 goto client_can_cache;
110 }
111
112 /* BB need same check in cifs_create too? */
113 /* if not oplocked, invalidate inode pages if mtime or file
114 size changed */
115 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
116 if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
117 (file->f_dentry->d_inode->i_size ==
118 (loff_t)le64_to_cpu(buf->EndOfFile))) {
119 cFYI(1, ("inode unchanged on server"));
120 } else {
121 if (file->f_dentry->d_inode->i_mapping) {
122 /* BB no need to lock inode until after invalidate
123 since namei code should already have it locked? */
124 filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
125 filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
126 }
127 cFYI(1, ("invalidating remote inode since open detected it "
128 "changed"));
129 invalidate_remote_inode(file->f_dentry->d_inode);
130 }
131
132client_can_cache:
133 if (pTcon->ses->capabilities & CAP_UNIX)
134 rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
135 full_path, inode->i_sb, xid);
136 else
137 rc = cifs_get_inode_info(&file->f_dentry->d_inode,
138 full_path, buf, inode->i_sb, xid);
139
140 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
141 pCifsInode->clientCanCacheAll = TRUE;
142 pCifsInode->clientCanCacheRead = TRUE;
143 cFYI(1, ("Exclusive Oplock granted on inode %p",
144 file->f_dentry->d_inode));
145 } else if ((*oplock & 0xF) == OPLOCK_READ)
146 pCifsInode->clientCanCacheRead = TRUE;
147
148 return rc;
149}
150
151int cifs_open(struct inode *inode, struct file *file)
152{
153 int rc = -EACCES;
154 int xid, oplock;
155 struct cifs_sb_info *cifs_sb;
156 struct cifsTconInfo *pTcon;
157 struct cifsFileInfo *pCifsFile;
158 struct cifsInodeInfo *pCifsInode;
159 struct list_head *tmp;
160 char *full_path = NULL;
161 int desiredAccess;
162 int disposition;
163 __u16 netfid;
164 FILE_ALL_INFO *buf = NULL;
165
166 xid = GetXid();
167
168 cifs_sb = CIFS_SB(inode->i_sb);
169 pTcon = cifs_sb->tcon;
170
171 if (file->f_flags & O_CREAT) {
172 /* search inode for this file and fill in file->private_data */
173 pCifsInode = CIFS_I(file->f_dentry->d_inode);
174 read_lock(&GlobalSMBSeslock);
175 list_for_each(tmp, &pCifsInode->openFileList) {
176 pCifsFile = list_entry(tmp, struct cifsFileInfo,
177 flist);
178 if ((pCifsFile->pfile == NULL) &&
179 (pCifsFile->pid == current->tgid)) {
180 /* mode set in cifs_create */
181
182 /* needed for writepage */
183 pCifsFile->pfile = file;
184
185 file->private_data = pCifsFile;
186 break;
187 }
188 }
189 read_unlock(&GlobalSMBSeslock);
190 if (file->private_data != NULL) {
191 rc = 0;
192 FreeXid(xid);
193 return rc;
194 } else {
195 if (file->f_flags & O_EXCL)
196 cERROR(1, ("could not find file instance for "
197 "new file %p ", file));
198 }
199 }
200
201 down(&inode->i_sb->s_vfs_rename_sem);
Steve French7f573562005-08-30 11:32:14 -0700202 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 up(&inode->i_sb->s_vfs_rename_sem);
204 if (full_path == NULL) {
205 FreeXid(xid);
206 return -ENOMEM;
207 }
208
209 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
210 inode, file->f_flags, full_path));
211 desiredAccess = cifs_convert_flags(file->f_flags);
212
213/*********************************************************************
214 * open flag mapping table:
215 *
216 * POSIX Flag CIFS Disposition
217 * ---------- ----------------
218 * O_CREAT FILE_OPEN_IF
219 * O_CREAT | O_EXCL FILE_CREATE
220 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
221 * O_TRUNC FILE_OVERWRITE
222 * none of the above FILE_OPEN
223 *
224 * Note that there is not a direct match between disposition
225 * FILE_SUPERSEDE (ie create whether or not file exists although
226 * O_CREAT | O_TRUNC is similar but truncates the existing
227 * file rather than creating a new file as FILE_SUPERSEDE does
228 * (which uses the attributes / metadata passed in on open call)
229 *?
230 *? O_SYNC is a reasonable match to CIFS writethrough flag
231 *? and the read write flags match reasonably. O_LARGEFILE
232 *? is irrelevant because largefile support is always used
233 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
234 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
235 *********************************************************************/
236
237 disposition = cifs_get_disposition(file->f_flags);
238
239 if (oplockEnabled)
240 oplock = REQ_OPLOCK;
241 else
242 oplock = FALSE;
243
244 /* BB pass O_SYNC flag through on file attributes .. BB */
245
246 /* Also refresh inode by passing in file_info buf returned by SMBOpen
247 and calling get_inode_info with returned buf (at least helps
248 non-Unix server case) */
249
250 /* BB we can not do this if this is the second open of a file
251 and the first handle has writebehind data, we might be
252 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
253 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
254 if (!buf) {
255 rc = -ENOMEM;
256 goto out;
257 }
258 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
259 CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700260 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
261 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frencha9d02ad2005-08-24 23:06:05 -0700262 if (rc == -EIO) {
263 /* Old server, try legacy style OpenX */
264 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
265 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
266 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
267 & CIFS_MOUNT_MAP_SPECIAL_CHR);
268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 if (rc) {
270 cFYI(1, ("cifs_open returned 0x%x ", rc));
271 goto out;
272 }
273 file->private_data =
274 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
275 if (file->private_data == NULL) {
276 rc = -ENOMEM;
277 goto out;
278 }
279 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
280 write_lock(&file->f_owner.lock);
281 write_lock(&GlobalSMBSeslock);
282 list_add(&pCifsFile->tlist, &pTcon->openFileList);
283
284 pCifsInode = CIFS_I(file->f_dentry->d_inode);
285 if (pCifsInode) {
286 rc = cifs_open_inode_helper(inode, file, pCifsInode,
287 pCifsFile, pTcon,
288 &oplock, buf, full_path, xid);
289 } else {
290 write_unlock(&GlobalSMBSeslock);
291 write_unlock(&file->f_owner.lock);
292 }
293
294 if (oplock & CIFS_CREATE_ACTION) {
295 /* time to set mode which we can not set earlier due to
296 problems creating new read-only files */
297 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
298 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
299 inode->i_mode,
300 (__u64)-1, (__u64)-1, 0 /* dev */,
Steve French737b7582005-04-28 22:41:06 -0700301 cifs_sb->local_nls,
302 cifs_sb->mnt_cifs_flags &
303 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 } else {
305 /* BB implement via Windows security descriptors eg
306 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
307 -1, -1, local_nls);
308 in the meantime could set r/o dos attribute when
309 perms are eg: mode & 0222 == 0 */
310 }
311 }
312
313out:
314 kfree(buf);
315 kfree(full_path);
316 FreeXid(xid);
317 return rc;
318}
319
320/* Try to reaquire byte range locks that were released when session */
321/* to server was lost */
322static int cifs_relock_file(struct cifsFileInfo *cifsFile)
323{
324 int rc = 0;
325
326/* BB list all locks open on this file and relock */
327
328 return rc;
329}
330
331static int cifs_reopen_file(struct inode *inode, struct file *file,
332 int can_flush)
333{
334 int rc = -EACCES;
335 int xid, oplock;
336 struct cifs_sb_info *cifs_sb;
337 struct cifsTconInfo *pTcon;
338 struct cifsFileInfo *pCifsFile;
339 struct cifsInodeInfo *pCifsInode;
340 char *full_path = NULL;
341 int desiredAccess;
342 int disposition = FILE_OPEN;
343 __u16 netfid;
344
345 if (inode == NULL)
346 return -EBADF;
347 if (file->private_data) {
348 pCifsFile = (struct cifsFileInfo *)file->private_data;
349 } else
350 return -EBADF;
351
352 xid = GetXid();
353 down(&pCifsFile->fh_sem);
354 if (pCifsFile->invalidHandle == FALSE) {
355 up(&pCifsFile->fh_sem);
356 FreeXid(xid);
357 return 0;
358 }
359
360 if (file->f_dentry == NULL) {
361 up(&pCifsFile->fh_sem);
362 cFYI(1, ("failed file reopen, no valid name if dentry freed"));
363 FreeXid(xid);
364 return -EBADF;
365 }
366 cifs_sb = CIFS_SB(inode->i_sb);
367 pTcon = cifs_sb->tcon;
368/* can not grab rename sem here because various ops, including
369 those that already have the rename sem can end up causing writepage
370 to get called and if the server was down that means we end up here,
371 and we can never tell if the caller already has the rename_sem */
Steve French7f573562005-08-30 11:32:14 -0700372 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 if (full_path == NULL) {
374 up(&pCifsFile->fh_sem);
375 FreeXid(xid);
376 return -ENOMEM;
377 }
378
379 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
380 inode, file->f_flags,full_path));
381 desiredAccess = cifs_convert_flags(file->f_flags);
382
383 if (oplockEnabled)
384 oplock = REQ_OPLOCK;
385 else
386 oplock = FALSE;
387
388 /* Can not refresh inode by passing in file_info buf to be returned
389 by SMBOpen and then calling get_inode_info with returned buf
390 since file might have write behind data that needs to be flushed
391 and server version of file size can be stale. If we knew for sure
392 that inode was not dirty locally we could do this */
393
394/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
395 if (buf == 0) {
396 up(&pCifsFile->fh_sem);
397 kfree(full_path);
398 FreeXid(xid);
399 return -ENOMEM;
400 } */
401 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
402 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700403 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
404 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (rc) {
406 up(&pCifsFile->fh_sem);
407 cFYI(1, ("cifs_open returned 0x%x ", rc));
408 cFYI(1, ("oplock: %d ", oplock));
409 } else {
410 pCifsFile->netfid = netfid;
411 pCifsFile->invalidHandle = FALSE;
412 up(&pCifsFile->fh_sem);
413 pCifsInode = CIFS_I(inode);
414 if (pCifsInode) {
415 if (can_flush) {
416 filemap_fdatawrite(inode->i_mapping);
417 filemap_fdatawait(inode->i_mapping);
418 /* temporarily disable caching while we
419 go to server to get inode info */
420 pCifsInode->clientCanCacheAll = FALSE;
421 pCifsInode->clientCanCacheRead = FALSE;
422 if (pTcon->ses->capabilities & CAP_UNIX)
423 rc = cifs_get_inode_info_unix(&inode,
424 full_path, inode->i_sb, xid);
425 else
426 rc = cifs_get_inode_info(&inode,
427 full_path, NULL, inode->i_sb,
428 xid);
429 } /* else we are writing out data to server already
430 and could deadlock if we tried to flush data, and
431 since we do not know if we have data that would
432 invalidate the current end of file on the server
433 we can not go to the server to get the new inod
434 info */
435 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
436 pCifsInode->clientCanCacheAll = TRUE;
437 pCifsInode->clientCanCacheRead = TRUE;
438 cFYI(1, ("Exclusive Oplock granted on inode %p",
439 file->f_dentry->d_inode));
440 } else if ((oplock & 0xF) == OPLOCK_READ) {
441 pCifsInode->clientCanCacheRead = TRUE;
442 pCifsInode->clientCanCacheAll = FALSE;
443 } else {
444 pCifsInode->clientCanCacheRead = FALSE;
445 pCifsInode->clientCanCacheAll = FALSE;
446 }
447 cifs_relock_file(pCifsFile);
448 }
449 }
450
451 kfree(full_path);
452 FreeXid(xid);
453 return rc;
454}
455
456int cifs_close(struct inode *inode, struct file *file)
457{
458 int rc = 0;
459 int xid;
460 struct cifs_sb_info *cifs_sb;
461 struct cifsTconInfo *pTcon;
462 struct cifsFileInfo *pSMBFile =
463 (struct cifsFileInfo *)file->private_data;
464
465 xid = GetXid();
466
467 cifs_sb = CIFS_SB(inode->i_sb);
468 pTcon = cifs_sb->tcon;
469 if (pSMBFile) {
470 pSMBFile->closePend = TRUE;
471 write_lock(&file->f_owner.lock);
472 if (pTcon) {
473 /* no sense reconnecting to close a file that is
474 already closed */
475 if (pTcon->tidStatus != CifsNeedReconnect) {
476 write_unlock(&file->f_owner.lock);
477 rc = CIFSSMBClose(xid, pTcon,
478 pSMBFile->netfid);
479 write_lock(&file->f_owner.lock);
480 }
481 }
Steve Frenchcbe04762005-04-28 22:41:05 -0700482 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 list_del(&pSMBFile->flist);
484 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700485 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 write_unlock(&file->f_owner.lock);
487 kfree(pSMBFile->search_resume_name);
488 kfree(file->private_data);
489 file->private_data = NULL;
490 } else
491 rc = -EBADF;
492
493 if (list_empty(&(CIFS_I(inode)->openFileList))) {
494 cFYI(1, ("closing last open instance for inode %p", inode));
495 /* if the file is not open we do not know if we can cache info
496 on this inode, much less write behind and read ahead */
497 CIFS_I(inode)->clientCanCacheRead = FALSE;
498 CIFS_I(inode)->clientCanCacheAll = FALSE;
499 }
500 if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
501 rc = CIFS_I(inode)->write_behind_rc;
502 FreeXid(xid);
503 return rc;
504}
505
506int cifs_closedir(struct inode *inode, struct file *file)
507{
508 int rc = 0;
509 int xid;
510 struct cifsFileInfo *pCFileStruct =
511 (struct cifsFileInfo *)file->private_data;
512 char *ptmp;
513
514 cFYI(1, ("Closedir inode = 0x%p with ", inode));
515
516 xid = GetXid();
517
518 if (pCFileStruct) {
519 struct cifsTconInfo *pTcon;
520 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
521
522 pTcon = cifs_sb->tcon;
523
524 cFYI(1, ("Freeing private data in close dir"));
Steve French31ca3bc2005-04-28 22:41:11 -0700525 if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
526 (pCFileStruct->invalidHandle == FALSE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 pCFileStruct->invalidHandle = TRUE;
528 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
529 cFYI(1, ("Closing uncompleted readdir with rc %d",
530 rc));
531 /* not much we can do if it fails anyway, ignore rc */
532 rc = 0;
533 }
534 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
535 if (ptmp) {
536 /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir"));
537 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
538 cifs_buf_release(ptmp);
539 }
540 ptmp = pCFileStruct->search_resume_name;
541 if (ptmp) {
542 /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir"));
543 pCFileStruct->search_resume_name = NULL;
544 kfree(ptmp);
545 }
546 kfree(file->private_data);
547 file->private_data = NULL;
548 }
549 /* BB can we lock the filestruct while this is going on? */
550 FreeXid(xid);
551 return rc;
552}
553
554int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
555{
556 int rc, xid;
557 __u32 lockType = LOCKING_ANDX_LARGE_FILES;
558 __u32 numLock = 0;
559 __u32 numUnlock = 0;
560 __u64 length;
561 int wait_flag = FALSE;
562 struct cifs_sb_info *cifs_sb;
563 struct cifsTconInfo *pTcon;
564
565 length = 1 + pfLock->fl_end - pfLock->fl_start;
566 rc = -EACCES;
567 xid = GetXid();
568
569 cFYI(1, ("Lock parm: 0x%x flockflags: "
570 "0x%x flocktype: 0x%x start: %lld end: %lld",
571 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
572 pfLock->fl_end));
573
574 if (pfLock->fl_flags & FL_POSIX)
575 cFYI(1, ("Posix "));
576 if (pfLock->fl_flags & FL_FLOCK)
577 cFYI(1, ("Flock "));
578 if (pfLock->fl_flags & FL_SLEEP) {
579 cFYI(1, ("Blocking lock "));
580 wait_flag = TRUE;
581 }
582 if (pfLock->fl_flags & FL_ACCESS)
583 cFYI(1, ("Process suspended by mandatory locking - "
584 "not implemented yet "));
585 if (pfLock->fl_flags & FL_LEASE)
586 cFYI(1, ("Lease on file - not implemented yet"));
587 if (pfLock->fl_flags &
588 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
589 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
590
591 if (pfLock->fl_type == F_WRLCK) {
592 cFYI(1, ("F_WRLCK "));
593 numLock = 1;
594 } else if (pfLock->fl_type == F_UNLCK) {
595 cFYI(1, ("F_UNLCK "));
596 numUnlock = 1;
597 } else if (pfLock->fl_type == F_RDLCK) {
598 cFYI(1, ("F_RDLCK "));
599 lockType |= LOCKING_ANDX_SHARED_LOCK;
600 numLock = 1;
601 } else if (pfLock->fl_type == F_EXLCK) {
602 cFYI(1, ("F_EXLCK "));
603 numLock = 1;
604 } else if (pfLock->fl_type == F_SHLCK) {
605 cFYI(1, ("F_SHLCK "));
606 lockType |= LOCKING_ANDX_SHARED_LOCK;
607 numLock = 1;
608 } else
609 cFYI(1, ("Unknown type of lock "));
610
611 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
612 pTcon = cifs_sb->tcon;
613
614 if (file->private_data == NULL) {
615 FreeXid(xid);
616 return -EBADF;
617 }
618
619 if (IS_GETLK(cmd)) {
620 rc = CIFSSMBLock(xid, pTcon,
621 ((struct cifsFileInfo *)file->
622 private_data)->netfid,
623 length,
624 pfLock->fl_start, 0, 1, lockType,
625 0 /* wait flag */ );
626 if (rc == 0) {
627 rc = CIFSSMBLock(xid, pTcon,
628 ((struct cifsFileInfo *) file->
629 private_data)->netfid,
630 length,
631 pfLock->fl_start, 1 /* numUnlock */ ,
632 0 /* numLock */ , lockType,
633 0 /* wait flag */ );
634 pfLock->fl_type = F_UNLCK;
635 if (rc != 0)
636 cERROR(1, ("Error unlocking previously locked "
637 "range %d during test of lock ",
638 rc));
639 rc = 0;
640
641 } else {
642 /* if rc == ERR_SHARING_VIOLATION ? */
643 rc = 0; /* do not change lock type to unlock
644 since range in use */
645 }
646
647 FreeXid(xid);
648 return rc;
649 }
650
651 rc = CIFSSMBLock(xid, pTcon,
652 ((struct cifsFileInfo *) file->private_data)->
653 netfid, length,
654 pfLock->fl_start, numUnlock, numLock, lockType,
655 wait_flag);
Steve Frenchd634cc12005-08-26 14:42:59 -0500656 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 posix_lock_file_wait(file, pfLock);
658 FreeXid(xid);
659 return rc;
660}
661
662ssize_t cifs_user_write(struct file *file, const char __user *write_data,
663 size_t write_size, loff_t *poffset)
664{
665 int rc = 0;
666 unsigned int bytes_written = 0;
667 unsigned int total_written;
668 struct cifs_sb_info *cifs_sb;
669 struct cifsTconInfo *pTcon;
670 int xid, long_op;
671 struct cifsFileInfo *open_file;
672
673 if (file->f_dentry == NULL)
674 return -EBADF;
675
676 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
677 if (cifs_sb == NULL)
678 return -EBADF;
679
680 pTcon = cifs_sb->tcon;
681
682 /* cFYI(1,
683 (" write %d bytes to offset %lld of %s", write_size,
684 *poffset, file->f_dentry->d_name.name)); */
685
686 if (file->private_data == NULL)
687 return -EBADF;
688 else
689 open_file = (struct cifsFileInfo *) file->private_data;
690
691 xid = GetXid();
692 if (file->f_dentry->d_inode == NULL) {
693 FreeXid(xid);
694 return -EBADF;
695 }
696
697 if (*poffset > file->f_dentry->d_inode->i_size)
698 long_op = 2; /* writes past end of file can take a long time */
699 else
700 long_op = 1;
701
702 for (total_written = 0; write_size > total_written;
703 total_written += bytes_written) {
704 rc = -EAGAIN;
705 while (rc == -EAGAIN) {
706 if (file->private_data == NULL) {
707 /* file has been closed on us */
708 FreeXid(xid);
709 /* if we have gotten here we have written some data
710 and blocked, and the file has been freed on us while
711 we blocked so return what we managed to write */
712 return total_written;
713 }
714 if (open_file->closePend) {
715 FreeXid(xid);
716 if (total_written)
717 return total_written;
718 else
719 return -EBADF;
720 }
721 if (open_file->invalidHandle) {
722 if ((file->f_dentry == NULL) ||
723 (file->f_dentry->d_inode == NULL)) {
724 FreeXid(xid);
725 return total_written;
726 }
727 /* we could deadlock if we called
728 filemap_fdatawait from here so tell
729 reopen_file not to flush data to server
730 now */
731 rc = cifs_reopen_file(file->f_dentry->d_inode,
732 file, FALSE);
733 if (rc != 0)
734 break;
735 }
736
737 rc = CIFSSMBWrite(xid, pTcon,
738 open_file->netfid,
739 min_t(const int, cifs_sb->wsize,
740 write_size - total_written),
741 *poffset, &bytes_written,
742 NULL, write_data + total_written, long_op);
743 }
744 if (rc || (bytes_written == 0)) {
745 if (total_written)
746 break;
747 else {
748 FreeXid(xid);
749 return rc;
750 }
751 } else
752 *poffset += bytes_written;
753 long_op = FALSE; /* subsequent writes fast -
754 15 seconds is plenty */
755 }
756
Steve Frencha4544342005-08-24 13:59:35 -0700757 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
759 /* since the write may have blocked check these pointers again */
760 if (file->f_dentry) {
761 if (file->f_dentry->d_inode) {
762 struct inode *inode = file->f_dentry->d_inode;
763 inode->i_ctime = inode->i_mtime =
764 current_fs_time(inode->i_sb);
765 if (total_written > 0) {
766 if (*poffset > file->f_dentry->d_inode->i_size)
767 i_size_write(file->f_dentry->d_inode,
768 *poffset);
769 }
770 mark_inode_dirty_sync(file->f_dentry->d_inode);
771 }
772 }
773 FreeXid(xid);
774 return total_written;
775}
776
777static ssize_t cifs_write(struct file *file, const char *write_data,
778 size_t write_size, loff_t *poffset)
779{
780 int rc = 0;
781 unsigned int bytes_written = 0;
782 unsigned int total_written;
783 struct cifs_sb_info *cifs_sb;
784 struct cifsTconInfo *pTcon;
785 int xid, long_op;
786 struct cifsFileInfo *open_file;
787
788 if (file->f_dentry == NULL)
789 return -EBADF;
790
791 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
792 if (cifs_sb == NULL)
793 return -EBADF;
794
795 pTcon = cifs_sb->tcon;
796
Steve Frenchab2f2182005-09-15 20:44:50 -0700797 cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
798 *poffset, file->f_dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 if (file->private_data == NULL)
801 return -EBADF;
802 else
803 open_file = (struct cifsFileInfo *)file->private_data;
804
805 xid = GetXid();
806 if (file->f_dentry->d_inode == NULL) {
807 FreeXid(xid);
808 return -EBADF;
809 }
810
811 if (*poffset > file->f_dentry->d_inode->i_size)
812 long_op = 2; /* writes past end of file can take a long time */
813 else
814 long_op = 1;
815
816 for (total_written = 0; write_size > total_written;
817 total_written += bytes_written) {
818 rc = -EAGAIN;
819 while (rc == -EAGAIN) {
820 if (file->private_data == NULL) {
821 /* file has been closed on us */
822 FreeXid(xid);
823 /* if we have gotten here we have written some data
824 and blocked, and the file has been freed on us
825 while we blocked so return what we managed to
826 write */
827 return total_written;
828 }
829 if (open_file->closePend) {
830 FreeXid(xid);
831 if (total_written)
832 return total_written;
833 else
834 return -EBADF;
835 }
836 if (open_file->invalidHandle) {
837 if ((file->f_dentry == NULL) ||
838 (file->f_dentry->d_inode == NULL)) {
839 FreeXid(xid);
840 return total_written;
841 }
842 /* we could deadlock if we called
843 filemap_fdatawait from here so tell
844 reopen_file not to flush data to
845 server now */
846 rc = cifs_reopen_file(file->f_dentry->d_inode,
847 file, FALSE);
848 if (rc != 0)
849 break;
850 }
Steve French0c0ff092005-06-23 19:31:17 -0500851#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500852 /* BB FIXME We can not sign across two buffers yet */
Steve French0c0ff092005-06-23 19:31:17 -0500853 if((experimEnabled) && ((pTcon->ses->server->secMode &
854 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
Steve French3e844692005-10-03 13:37:24 -0700855 struct kvec iov[2];
856 unsigned int len;
857
858 len = min(cifs_sb->wsize,
859 write_size - total_written);
860 /* iov[0] is reserved for smb header */
861 iov[1].iov_base = (char *)write_data +
862 total_written;
863 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500864 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -0700865 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500866 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -0700867 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500868 } else
869 /* BB FIXME fixup indentation of line below */
870#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 rc = CIFSSMBWrite(xid, pTcon,
872 open_file->netfid,
873 min_t(const int, cifs_sb->wsize,
874 write_size - total_written),
875 *poffset, &bytes_written,
876 write_data + total_written, NULL, long_op);
877 }
878 if (rc || (bytes_written == 0)) {
879 if (total_written)
880 break;
881 else {
882 FreeXid(xid);
883 return rc;
884 }
885 } else
886 *poffset += bytes_written;
887 long_op = FALSE; /* subsequent writes fast -
888 15 seconds is plenty */
889 }
890
Steve Frencha4544342005-08-24 13:59:35 -0700891 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 /* since the write may have blocked check these pointers again */
894 if (file->f_dentry) {
895 if (file->f_dentry->d_inode) {
896 file->f_dentry->d_inode->i_ctime =
897 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
898 if (total_written > 0) {
899 if (*poffset > file->f_dentry->d_inode->i_size)
900 i_size_write(file->f_dentry->d_inode,
901 *poffset);
902 }
903 mark_inode_dirty_sync(file->f_dentry->d_inode);
904 }
905 }
906 FreeXid(xid);
907 return total_written;
908}
909
Steve Frenchdd99cd82005-10-05 19:32:49 -0700910struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -0700911{
912 struct cifsFileInfo *open_file;
Steve Frenchdd99cd82005-10-05 19:32:49 -0700913 int rc;
Steve French6148a742005-10-05 12:23:19 -0700914
915 read_lock(&GlobalSMBSeslock);
916 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
917 if (open_file->closePend)
918 continue;
919 if (open_file->pfile &&
920 ((open_file->pfile->f_flags & O_RDWR) ||
921 (open_file->pfile->f_flags & O_WRONLY))) {
922 read_unlock(&GlobalSMBSeslock);
Steve French37c0eb42005-10-05 14:50:29 -0700923 if(open_file->invalidHandle) {
Steve Frenchdd99cd82005-10-05 19:32:49 -0700924 rc = cifs_reopen_file(&cifs_inode->vfs_inode,
Steve French37c0eb42005-10-05 14:50:29 -0700925 open_file->pfile, FALSE);
926 /* if it fails, try another handle - might be */
927 /* dangerous to hold up writepages with retry */
928 if(rc) {
Steve French4a771182005-10-05 15:14:33 -0700929 cFYI(1,("failed on reopen file in wp"));
Steve French37c0eb42005-10-05 14:50:29 -0700930 read_lock(&GlobalSMBSeslock);
931 continue;
932 }
933 }
Steve French6148a742005-10-05 12:23:19 -0700934 return open_file;
935 }
936 }
937 read_unlock(&GlobalSMBSeslock);
938 return NULL;
939}
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
942{
943 struct address_space *mapping = page->mapping;
944 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
945 char *write_data;
946 int rc = -EFAULT;
947 int bytes_written = 0;
948 struct cifs_sb_info *cifs_sb;
949 struct cifsTconInfo *pTcon;
950 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -0700951 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 if (!mapping || !mapping->host)
954 return -EFAULT;
955
956 inode = page->mapping->host;
957 cifs_sb = CIFS_SB(inode->i_sb);
958 pTcon = cifs_sb->tcon;
959
960 offset += (loff_t)from;
961 write_data = kmap(page);
962 write_data += from;
963
964 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
965 kunmap(page);
966 return -EIO;
967 }
968
969 /* racing with truncate? */
970 if (offset > mapping->host->i_size) {
971 kunmap(page);
972 return 0; /* don't care */
973 }
974
975 /* check to make sure that we are not extending the file */
976 if (mapping->host->i_size - offset < (loff_t)to)
977 to = (unsigned)(mapping->host->i_size - offset);
978
Steve French6148a742005-10-05 12:23:19 -0700979 open_file = find_writable_file(CIFS_I(mapping->host));
980 if (open_file) {
981 bytes_written = cifs_write(open_file->pfile, write_data,
982 to-from, &offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -0700984 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
985 if ((bytes_written > 0) && (offset)) {
986 rc = 0;
987 } else if (bytes_written < 0) {
988 if (rc != -EBADF)
989 rc = bytes_written;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
Steve French6148a742005-10-05 12:23:19 -0700991 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 cFYI(1, ("No writeable filehandles for inode"));
993 rc = -EIO;
994 }
995
996 kunmap(page);
997 return rc;
998}
999
Steve French37c0eb42005-10-05 14:50:29 -07001000#ifdef CONFIG_CIFS_EXPERIMENTAL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001002 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003{
Steve French37c0eb42005-10-05 14:50:29 -07001004 struct backing_dev_info *bdi = mapping->backing_dev_info;
1005 unsigned int bytes_to_write;
1006 unsigned int bytes_written;
1007 struct cifs_sb_info *cifs_sb;
1008 int done = 0;
1009 pgoff_t end = -1;
1010 pgoff_t index;
1011 int is_range = 0;
1012 struct kvec iov[32];
1013 int n_iov = 0;
1014 pgoff_t next;
1015 int nr_pages;
1016 __u64 offset = 0;
1017 struct cifsFileInfo *open_file = NULL;
1018 struct page *page;
1019 struct pagevec pvec;
1020 int rc = 0;
1021 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 int xid;
1023
Steve French37c0eb42005-10-05 14:50:29 -07001024 cifs_sb = CIFS_SB(mapping->host->i_sb);
1025
1026 /*
1027 * If wsize is smaller that the page cache size, default to writing
1028 * one page at a time via cifs_writepage
1029 */
1030 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1031 return generic_writepages(mapping, wbc);
1032
Steve French4a771182005-10-05 15:14:33 -07001033 /* BB FIXME we do not have code to sign across multiple buffers yet,
1034 so go to older writepage style write which we can sign if needed */
1035 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1036 if(cifs_sb->tcon->ses->server->secMode &
1037 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1038 return generic_writepages(mapping, wbc);
1039
Steve French37c0eb42005-10-05 14:50:29 -07001040 /*
1041 * BB: Is this meaningful for a non-block-device file system?
1042 * If it is, we should test it again after we do I/O
1043 */
1044 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1045 wbc->encountered_congestion = 1;
1046 return 0;
1047 }
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 xid = GetXid();
1050
Steve French37c0eb42005-10-05 14:50:29 -07001051 pagevec_init(&pvec, 0);
1052 if (wbc->sync_mode == WB_SYNC_NONE)
1053 index = mapping->writeback_index; /* Start from prev offset */
1054 else {
1055 index = 0;
1056 scanned = 1;
1057 }
1058 if (wbc->start || wbc->end) {
1059 index = wbc->start >> PAGE_CACHE_SHIFT;
1060 end = wbc->end >> PAGE_CACHE_SHIFT;
1061 is_range = 1;
1062 scanned = 1;
1063 }
1064retry:
1065 while (!done && (index <= end) &&
1066 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1067 PAGECACHE_TAG_DIRTY,
1068 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1069 int first;
1070 unsigned int i;
1071
1072 if (!open_file) {
1073 open_file = find_writable_file(CIFS_I(mapping->host));
1074 if (!open_file) {
1075 pagevec_release(&pvec);
1076 cERROR(1, ("No writable handles for inode"));
1077 return -EIO;
1078 }
1079 }
1080
1081 first = -1;
1082 next = 0;
1083 n_iov = 0;
1084 bytes_to_write = 0;
1085
1086 for (i = 0; i < nr_pages; i++) {
1087 page = pvec.pages[i];
1088 /*
1089 * At this point we hold neither mapping->tree_lock nor
1090 * lock on the page itself: the page may be truncated or
1091 * invalidated (changing page->mapping to NULL), or even
1092 * swizzled back from swapper_space to tmpfs file
1093 * mapping
1094 */
1095
1096 if (first < 0)
1097 lock_page(page);
1098 else if (TestSetPageLocked(page))
1099 break;
1100
1101 if (unlikely(page->mapping != mapping)) {
1102 unlock_page(page);
1103 break;
1104 }
1105
1106 if (unlikely(is_range) && (page->index > end)) {
1107 done = 1;
1108 unlock_page(page);
1109 break;
1110 }
1111
1112 if (next && (page->index != next)) {
1113 /* Not next consecutive page */
1114 unlock_page(page);
1115 break;
1116 }
1117
1118 if (wbc->sync_mode != WB_SYNC_NONE)
1119 wait_on_page_writeback(page);
1120
1121 if (PageWriteback(page) ||
1122 !test_clear_page_dirty(page)) {
1123 unlock_page(page);
1124 break;
1125 }
1126 /*
1127 * BB can we get rid of this? pages are held by pvec
1128 */
1129 page_cache_get(page);
1130
1131 /* reserve iov[0] for the smb header */
1132 n_iov++;
1133 iov[n_iov].iov_base = kmap(page);
1134 iov[n_iov].iov_len = PAGE_CACHE_SIZE;
1135 bytes_to_write += PAGE_CACHE_SIZE;
1136
1137 if (first < 0) {
1138 first = i;
1139 offset = page_offset(page);
1140 }
1141 next = page->index + 1;
1142 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1143 break;
1144 }
1145 if (n_iov) {
1146 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1147 open_file->netfid, bytes_to_write,
1148 offset, &bytes_written, iov, n_iov,
1149 1);
1150 if (rc || bytes_written < bytes_to_write) {
1151 cERROR(1,("CIFSSMBWrite2 returned %d, written = %x",
1152 rc, bytes_written));
1153 set_bit(AS_EIO, &mapping->flags);
1154 SetPageError(page);
1155 }
1156 for (i = 0; i < n_iov; i++) {
1157 page = pvec.pages[first + i];
1158 kunmap(page);
1159 unlock_page(page);
1160 page_cache_release(page);
1161 }
1162 if ((wbc->nr_to_write -= n_iov) <= 0)
1163 done = 1;
1164 index = next;
1165 }
1166 pagevec_release(&pvec);
1167 }
1168 if (!scanned && !done) {
1169 /*
1170 * We hit the last page and there is more work to be done: wrap
1171 * back to the start of the file
1172 */
1173 scanned = 1;
1174 index = 0;
1175 goto retry;
1176 }
1177 if (!is_range)
1178 mapping->writeback_index = index;
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 FreeXid(xid);
Steve French37c0eb42005-10-05 14:50:29 -07001181
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return rc;
1183}
1184#endif
1185
1186static int cifs_writepage(struct page* page, struct writeback_control *wbc)
1187{
1188 int rc = -EFAULT;
1189 int xid;
1190
1191 xid = GetXid();
1192/* BB add check for wbc flags */
1193 page_cache_get(page);
1194 if (!PageUptodate(page)) {
1195 cFYI(1, ("ppw - page not up to date"));
1196 }
1197
1198 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1199 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1200 unlock_page(page);
1201 page_cache_release(page);
1202 FreeXid(xid);
1203 return rc;
1204}
1205
1206static int cifs_commit_write(struct file *file, struct page *page,
1207 unsigned offset, unsigned to)
1208{
1209 int xid;
1210 int rc = 0;
1211 struct inode *inode = page->mapping->host;
1212 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1213 char *page_data;
1214
1215 xid = GetXid();
1216 cFYI(1, ("commit write for page %p up to position %lld for %d",
1217 page, position, to));
1218 if (position > inode->i_size) {
1219 i_size_write(inode, position);
1220 /* if (file->private_data == NULL) {
1221 rc = -EBADF;
1222 } else {
1223 open_file = (struct cifsFileInfo *)file->private_data;
1224 cifs_sb = CIFS_SB(inode->i_sb);
1225 rc = -EAGAIN;
1226 while (rc == -EAGAIN) {
1227 if ((open_file->invalidHandle) &&
1228 (!open_file->closePend)) {
1229 rc = cifs_reopen_file(
1230 file->f_dentry->d_inode, file);
1231 if (rc != 0)
1232 break;
1233 }
1234 if (!open_file->closePend) {
1235 rc = CIFSSMBSetFileSize(xid,
1236 cifs_sb->tcon, position,
1237 open_file->netfid,
1238 open_file->pid, FALSE);
1239 } else {
1240 rc = -EBADF;
1241 break;
1242 }
1243 }
1244 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1245 } */
1246 }
1247 if (!PageUptodate(page)) {
1248 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1249 /* can not rely on (or let) writepage write this data */
1250 if (to < offset) {
1251 cFYI(1, ("Illegal offsets, can not copy from %d to %d",
1252 offset, to));
1253 FreeXid(xid);
1254 return rc;
1255 }
1256 /* this is probably better than directly calling
1257 partialpage_write since in this function the file handle is
1258 known which we might as well leverage */
1259 /* BB check if anything else missing out of ppw
1260 such as updating last write time */
1261 page_data = kmap(page);
1262 rc = cifs_write(file, page_data + offset, to-offset,
1263 &position);
1264 if (rc > 0)
1265 rc = 0;
1266 /* else if (rc < 0) should we set writebehind rc? */
1267 kunmap(page);
1268 } else {
1269 set_page_dirty(page);
1270 }
1271
1272 FreeXid(xid);
1273 return rc;
1274}
1275
1276int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1277{
1278 int xid;
1279 int rc = 0;
1280 struct inode *inode = file->f_dentry->d_inode;
1281
1282 xid = GetXid();
1283
1284 cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
1285 dentry->d_name.name, datasync));
1286
1287 rc = filemap_fdatawrite(inode->i_mapping);
1288 if (rc == 0)
1289 CIFS_I(inode)->write_behind_rc = 0;
1290 FreeXid(xid);
1291 return rc;
1292}
1293
1294/* static int cifs_sync_page(struct page *page)
1295{
1296 struct address_space *mapping;
1297 struct inode *inode;
1298 unsigned long index = page->index;
1299 unsigned int rpages = 0;
1300 int rc = 0;
1301
1302 cFYI(1, ("sync page %p",page));
1303 mapping = page->mapping;
1304 if (!mapping)
1305 return 0;
1306 inode = mapping->host;
1307 if (!inode)
1308 return 0; */
1309
1310/* fill in rpages then
1311 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1312
1313/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
1314
1315 if (rc < 0)
1316 return rc;
1317 return 0;
1318} */
1319
1320/*
1321 * As file closes, flush all cached write data for this inode checking
1322 * for write behind errors.
1323 */
1324int cifs_flush(struct file *file)
1325{
1326 struct inode * inode = file->f_dentry->d_inode;
1327 int rc = 0;
1328
1329 /* Rather than do the steps manually:
1330 lock the inode for writing
1331 loop through pages looking for write behind data (dirty pages)
1332 coalesce into contiguous 16K (or smaller) chunks to write to server
1333 send to server (prefer in parallel)
1334 deal with writebehind errors
1335 unlock inode for writing
1336 filemapfdatawrite appears easier for the time being */
1337
1338 rc = filemap_fdatawrite(inode->i_mapping);
1339 if (!rc) /* reset wb rc if we were able to write out dirty pages */
1340 CIFS_I(inode)->write_behind_rc = 0;
1341
1342 cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
1343
1344 return rc;
1345}
1346
1347ssize_t cifs_user_read(struct file *file, char __user *read_data,
1348 size_t read_size, loff_t *poffset)
1349{
1350 int rc = -EACCES;
1351 unsigned int bytes_read = 0;
1352 unsigned int total_read = 0;
1353 unsigned int current_read_size;
1354 struct cifs_sb_info *cifs_sb;
1355 struct cifsTconInfo *pTcon;
1356 int xid;
1357 struct cifsFileInfo *open_file;
1358 char *smb_read_data;
1359 char __user *current_offset;
1360 struct smb_com_read_rsp *pSMBr;
1361
1362 xid = GetXid();
1363 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1364 pTcon = cifs_sb->tcon;
1365
1366 if (file->private_data == NULL) {
1367 FreeXid(xid);
1368 return -EBADF;
1369 }
1370 open_file = (struct cifsFileInfo *)file->private_data;
1371
1372 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1373 cFYI(1, ("attempting read on write only file instance"));
1374 }
1375 for (total_read = 0, current_offset = read_data;
1376 read_size > total_read;
1377 total_read += bytes_read, current_offset += bytes_read) {
1378 current_read_size = min_t(const int, read_size - total_read,
1379 cifs_sb->rsize);
1380 rc = -EAGAIN;
1381 smb_read_data = NULL;
1382 while (rc == -EAGAIN) {
1383 if ((open_file->invalidHandle) &&
1384 (!open_file->closePend)) {
1385 rc = cifs_reopen_file(file->f_dentry->d_inode,
1386 file, TRUE);
1387 if (rc != 0)
1388 break;
1389 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001390 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001391 open_file->netfid,
1392 current_read_size, *poffset,
1393 &bytes_read, &smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1395 if (copy_to_user(current_offset,
1396 smb_read_data + 4 /* RFC1001 hdr */
1397 + le16_to_cpu(pSMBr->DataOffset),
1398 bytes_read)) {
1399 rc = -EFAULT;
1400 FreeXid(xid);
1401 return rc;
1402 }
1403 if (smb_read_data) {
1404 cifs_buf_release(smb_read_data);
1405 smb_read_data = NULL;
1406 }
1407 }
1408 if (rc || (bytes_read == 0)) {
1409 if (total_read) {
1410 break;
1411 } else {
1412 FreeXid(xid);
1413 return rc;
1414 }
1415 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001416 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 *poffset += bytes_read;
1418 }
1419 }
1420 FreeXid(xid);
1421 return total_read;
1422}
1423
1424
1425static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1426 loff_t *poffset)
1427{
1428 int rc = -EACCES;
1429 unsigned int bytes_read = 0;
1430 unsigned int total_read;
1431 unsigned int current_read_size;
1432 struct cifs_sb_info *cifs_sb;
1433 struct cifsTconInfo *pTcon;
1434 int xid;
1435 char *current_offset;
1436 struct cifsFileInfo *open_file;
1437
1438 xid = GetXid();
1439 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1440 pTcon = cifs_sb->tcon;
1441
1442 if (file->private_data == NULL) {
1443 FreeXid(xid);
1444 return -EBADF;
1445 }
1446 open_file = (struct cifsFileInfo *)file->private_data;
1447
1448 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1449 cFYI(1, ("attempting read on write only file instance"));
1450
1451 for (total_read = 0, current_offset = read_data;
1452 read_size > total_read;
1453 total_read += bytes_read, current_offset += bytes_read) {
1454 current_read_size = min_t(const int, read_size - total_read,
1455 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001456 /* For windows me and 9x we do not want to request more
1457 than it negotiated since it will refuse the read then */
1458 if((pTcon->ses) &&
1459 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1460 current_read_size = min_t(const int, current_read_size,
1461 pTcon->ses->server->maxBuf - 128);
1462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 rc = -EAGAIN;
1464 while (rc == -EAGAIN) {
1465 if ((open_file->invalidHandle) &&
1466 (!open_file->closePend)) {
1467 rc = cifs_reopen_file(file->f_dentry->d_inode,
1468 file, TRUE);
1469 if (rc != 0)
1470 break;
1471 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001472 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001473 open_file->netfid,
1474 current_read_size, *poffset,
1475 &bytes_read, &current_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 if (rc || (bytes_read == 0)) {
1478 if (total_read) {
1479 break;
1480 } else {
1481 FreeXid(xid);
1482 return rc;
1483 }
1484 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001485 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 *poffset += bytes_read;
1487 }
1488 }
1489 FreeXid(xid);
1490 return total_read;
1491}
1492
1493int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1494{
1495 struct dentry *dentry = file->f_dentry;
1496 int rc, xid;
1497
1498 xid = GetXid();
1499 rc = cifs_revalidate(dentry);
1500 if (rc) {
1501 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1502 FreeXid(xid);
1503 return rc;
1504 }
1505 rc = generic_file_mmap(file, vma);
1506 FreeXid(xid);
1507 return rc;
1508}
1509
1510
1511static void cifs_copy_cache_pages(struct address_space *mapping,
1512 struct list_head *pages, int bytes_read, char *data,
1513 struct pagevec *plru_pvec)
1514{
1515 struct page *page;
1516 char *target;
1517
1518 while (bytes_read > 0) {
1519 if (list_empty(pages))
1520 break;
1521
1522 page = list_entry(pages->prev, struct page, lru);
1523 list_del(&page->lru);
1524
1525 if (add_to_page_cache(page, mapping, page->index,
1526 GFP_KERNEL)) {
1527 page_cache_release(page);
1528 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001529 data += PAGE_CACHE_SIZE;
1530 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 continue;
1532 }
1533
1534 target = kmap_atomic(page,KM_USER0);
1535
1536 if (PAGE_CACHE_SIZE > bytes_read) {
1537 memcpy(target, data, bytes_read);
1538 /* zero the tail end of this partial page */
1539 memset(target + bytes_read, 0,
1540 PAGE_CACHE_SIZE - bytes_read);
1541 bytes_read = 0;
1542 } else {
1543 memcpy(target, data, PAGE_CACHE_SIZE);
1544 bytes_read -= PAGE_CACHE_SIZE;
1545 }
1546 kunmap_atomic(target, KM_USER0);
1547
1548 flush_dcache_page(page);
1549 SetPageUptodate(page);
1550 unlock_page(page);
1551 if (!pagevec_add(plru_pvec, page))
1552 __pagevec_lru_add(plru_pvec);
1553 data += PAGE_CACHE_SIZE;
1554 }
1555 return;
1556}
1557
1558static int cifs_readpages(struct file *file, struct address_space *mapping,
1559 struct list_head *page_list, unsigned num_pages)
1560{
1561 int rc = -EACCES;
1562 int xid;
1563 loff_t offset;
1564 struct page *page;
1565 struct cifs_sb_info *cifs_sb;
1566 struct cifsTconInfo *pTcon;
1567 int bytes_read = 0;
1568 unsigned int read_size,i;
1569 char *smb_read_data = NULL;
1570 struct smb_com_read_rsp *pSMBr;
1571 struct pagevec lru_pvec;
1572 struct cifsFileInfo *open_file;
1573
1574 xid = GetXid();
1575 if (file->private_data == NULL) {
1576 FreeXid(xid);
1577 return -EBADF;
1578 }
1579 open_file = (struct cifsFileInfo *)file->private_data;
1580 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1581 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 pagevec_init(&lru_pvec, 0);
1584
1585 for (i = 0; i < num_pages; ) {
1586 unsigned contig_pages;
1587 struct page *tmp_page;
1588 unsigned long expected_index;
1589
1590 if (list_empty(page_list))
1591 break;
1592
1593 page = list_entry(page_list->prev, struct page, lru);
1594 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1595
1596 /* count adjacent pages that we will read into */
1597 contig_pages = 0;
1598 expected_index =
1599 list_entry(page_list->prev, struct page, lru)->index;
1600 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1601 if (tmp_page->index == expected_index) {
1602 contig_pages++;
1603 expected_index++;
1604 } else
1605 break;
1606 }
1607 if (contig_pages + i > num_pages)
1608 contig_pages = num_pages - i;
1609
1610 /* for reads over a certain size could initiate async
1611 read ahead */
1612
1613 read_size = contig_pages * PAGE_CACHE_SIZE;
1614 /* Read size needs to be in multiples of one page */
1615 read_size = min_t(const unsigned int, read_size,
1616 cifs_sb->rsize & PAGE_CACHE_MASK);
1617
1618 rc = -EAGAIN;
1619 while (rc == -EAGAIN) {
1620 if ((open_file->invalidHandle) &&
1621 (!open_file->closePend)) {
1622 rc = cifs_reopen_file(file->f_dentry->d_inode,
1623 file, TRUE);
1624 if (rc != 0)
1625 break;
1626 }
1627
Steve Frenchbfa0d752005-08-31 21:50:37 -07001628 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001629 open_file->netfid,
1630 read_size, offset,
1631 &bytes_read, &smb_read_data);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001632
1633 /* BB more RC checks ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (rc== -EAGAIN) {
1635 if (smb_read_data) {
1636 cifs_buf_release(smb_read_data);
1637 smb_read_data = NULL;
1638 }
1639 }
1640 }
1641 if ((rc < 0) || (smb_read_data == NULL)) {
1642 cFYI(1, ("Read error in readpages: %d", rc));
1643 /* clean up remaing pages off list */
1644 while (!list_empty(page_list) && (i < num_pages)) {
1645 page = list_entry(page_list->prev, struct page,
1646 lru);
1647 list_del(&page->lru);
1648 page_cache_release(page);
1649 }
1650 break;
1651 } else if (bytes_read > 0) {
1652 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1653 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1654 smb_read_data + 4 /* RFC1001 hdr */ +
1655 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1656
1657 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001658 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1660 i++; /* account for partial page */
1661
1662 /* server copy of file can have smaller size
1663 than client */
1664 /* BB do we need to verify this common case ?
1665 this case is ok - if we are at server EOF
1666 we will hit it on next read */
1667
1668 /* while (!list_empty(page_list) && (i < num_pages)) {
1669 page = list_entry(page_list->prev,
1670 struct page, list);
1671 list_del(&page->list);
1672 page_cache_release(page);
1673 }
1674 break; */
1675 }
1676 } else {
1677 cFYI(1, ("No bytes read (%d) at offset %lld . "
1678 "Cleaning remaining pages from readahead list",
1679 bytes_read, offset));
1680 /* BB turn off caching and do new lookup on
1681 file size at server? */
1682 while (!list_empty(page_list) && (i < num_pages)) {
1683 page = list_entry(page_list->prev, struct page,
1684 lru);
1685 list_del(&page->lru);
1686
1687 /* BB removeme - replace with zero of page? */
1688 page_cache_release(page);
1689 }
1690 break;
1691 }
1692 if (smb_read_data) {
1693 cifs_buf_release(smb_read_data);
1694 smb_read_data = NULL;
1695 }
1696 bytes_read = 0;
1697 }
1698
1699 pagevec_lru_add(&lru_pvec);
1700
1701/* need to free smb_read_data buf before exit */
1702 if (smb_read_data) {
1703 cifs_buf_release(smb_read_data);
1704 smb_read_data = NULL;
1705 }
1706
1707 FreeXid(xid);
1708 return rc;
1709}
1710
1711static int cifs_readpage_worker(struct file *file, struct page *page,
1712 loff_t *poffset)
1713{
1714 char *read_data;
1715 int rc;
1716
1717 page_cache_get(page);
1718 read_data = kmap(page);
1719 /* for reads over a certain size could initiate async read ahead */
1720
1721 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1722
1723 if (rc < 0)
1724 goto io_error;
1725 else
1726 cFYI(1, ("Bytes read %d ",rc));
1727
1728 file->f_dentry->d_inode->i_atime =
1729 current_fs_time(file->f_dentry->d_inode->i_sb);
1730
1731 if (PAGE_CACHE_SIZE > rc)
1732 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1733
1734 flush_dcache_page(page);
1735 SetPageUptodate(page);
1736 rc = 0;
1737
1738io_error:
1739 kunmap(page);
1740 page_cache_release(page);
1741 return rc;
1742}
1743
1744static int cifs_readpage(struct file *file, struct page *page)
1745{
1746 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1747 int rc = -EACCES;
1748 int xid;
1749
1750 xid = GetXid();
1751
1752 if (file->private_data == NULL) {
1753 FreeXid(xid);
1754 return -EBADF;
1755 }
1756
1757 cFYI(1, ("readpage %p at offset %d 0x%x\n",
1758 page, (int)offset, (int)offset));
1759
1760 rc = cifs_readpage_worker(file, page, &offset);
1761
1762 unlock_page(page);
1763
1764 FreeXid(xid);
1765 return rc;
1766}
1767
1768/* We do not want to update the file size from server for inodes
1769 open for write - to avoid races with writepage extending
1770 the file - in the future we could consider allowing
1771 refreshing the inode only on increases in the file size
1772 but this is tricky to do without racing with writebehind
1773 page caching in the current Linux kernel design */
1774int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1775{
Steve French6148a742005-10-05 12:23:19 -07001776 if (cifsInode && find_writable_file(cifsInode))
1777 return 0;
1778 else
1779 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780}
1781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782static int cifs_prepare_write(struct file *file, struct page *page,
1783 unsigned from, unsigned to)
1784{
1785 int rc = 0;
1786 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1787 cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
1788 if (!PageUptodate(page)) {
1789 /* if (to - from != PAGE_CACHE_SIZE) {
1790 void *kaddr = kmap_atomic(page, KM_USER0);
1791 memset(kaddr, 0, from);
1792 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1793 flush_dcache_page(page);
1794 kunmap_atomic(kaddr, KM_USER0);
1795 } */
1796 /* If we are writing a full page it will be up to date,
1797 no need to read from the server */
1798 if ((to == PAGE_CACHE_SIZE) && (from == 0))
1799 SetPageUptodate(page);
1800
1801 /* might as well read a page, it is fast enough */
1802 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
1803 rc = cifs_readpage_worker(file, page, &offset);
1804 } else {
1805 /* should we try using another file handle if there is one -
1806 how would we lock it to prevent close of that handle
1807 racing with this read?
1808 In any case this will be written out by commit_write */
1809 }
1810 }
1811
1812 /* BB should we pass any errors back?
1813 e.g. if we do not have read access to the file */
1814 return 0;
1815}
1816
1817struct address_space_operations cifs_addr_ops = {
1818 .readpage = cifs_readpage,
1819 .readpages = cifs_readpages,
1820 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07001821#ifdef CONFIG_CIFS_EXPERIMENTAL
1822 .writepages = cifs_writepages,
1823#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 .prepare_write = cifs_prepare_write,
1825 .commit_write = cifs_commit_write,
1826 .set_page_dirty = __set_page_dirty_nobuffers,
1827 /* .sync_page = cifs_sync_page, */
1828 /* .direct_IO = */
1829};