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