upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / 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 extern int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir); /* BB removeme BB */
39
40 int
41 cifs_open(struct inode *inode, struct file *file)
42 {
43         int rc = -EACCES;
44         int xid, oplock;
45         struct cifs_sb_info *cifs_sb;
46         struct cifsTconInfo *pTcon;
47         struct cifsFileInfo *pCifsFile;
48         struct cifsInodeInfo *pCifsInode;
49         struct list_head * tmp;
50         char *full_path = NULL;
51         int desiredAccess = 0x20197;
52         int disposition;
53         __u16 netfid;
54         FILE_ALL_INFO * buf = NULL;
55
56         xid = GetXid();
57
58         cifs_sb = CIFS_SB(inode->i_sb);
59         pTcon = cifs_sb->tcon;
60
61         if (file->f_flags & O_CREAT) {
62                 /* search inode for this file and fill in file->private_data = */
63                 pCifsInode = CIFS_I(file->f_dentry->d_inode);
64                 read_lock(&GlobalSMBSeslock);
65                 list_for_each(tmp, &pCifsInode->openFileList) {            
66                         pCifsFile = list_entry(tmp,struct cifsFileInfo, flist);           
67                         if((pCifsFile->pfile == NULL)&& (pCifsFile->pid == current->tgid)){
68                         /* mode set in cifs_create */
69                                 pCifsFile->pfile = file; /* needed for writepage */
70                                 file->private_data = pCifsFile;
71                                 break;
72                         }
73                 }
74                 read_unlock(&GlobalSMBSeslock);
75                 if(file->private_data != NULL) {
76                         rc = 0;
77                         FreeXid(xid);
78                         return rc;
79                 } else {
80                         if(file->f_flags & O_EXCL)
81                                 cERROR(1,("could not find file instance for new file %p ",file));
82                 }
83         }
84
85         down(&inode->i_sb->s_vfs_rename_sem);
86         full_path = build_path_from_dentry(file->f_dentry);
87         up(&inode->i_sb->s_vfs_rename_sem);
88         if(full_path == NULL) {
89                 FreeXid(xid);
90                 return -ENOMEM;
91         }
92
93         cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
94         if ((file->f_flags & O_ACCMODE) == O_RDONLY)
95                 desiredAccess = GENERIC_READ;
96         else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
97                 desiredAccess = GENERIC_WRITE;
98         else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
99                 /* GENERIC_ALL is too much permission to request */
100                 /* can cause unnecessary access denied on create */
101                 /* desiredAccess = GENERIC_ALL; */
102                 desiredAccess = GENERIC_READ | GENERIC_WRITE;
103         }
104
105 /*********************************************************************
106  *  open flag mapping table:
107  *  
108  *      POSIX Flag            CIFS Disposition
109  *      ----------            ---------------- 
110  *      O_CREAT               FILE_OPEN_IF
111  *      O_CREAT | O_EXCL      FILE_CREATE
112  *      O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
113  *      O_TRUNC               FILE_OVERWRITE
114  *      none of the above     FILE_OPEN
115  *
116  *      Note that there is not a direct match between disposition
117  *      FILE_SUPERSEDE (ie create whether or not file exists although 
118  *      O_CREAT | O_TRUNC is similar but truncates the existing
119  *      file rather than creating a new file as FILE_SUPERSEDE does
120  *      (which uses the attributes / metadata passed in on open call)
121  *?
122  *?  O_SYNC is a reasonable match to CIFS writethrough flag  
123  *?  and the read write flags match reasonably.  O_LARGEFILE
124  *?  is irrelevant because largefile support is always used
125  *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
126  *       O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
127  *********************************************************************/
128
129         if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
130                 disposition = FILE_CREATE;
131         else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
132                 disposition = FILE_OVERWRITE_IF;
133         else if((file->f_flags & O_CREAT) == O_CREAT)
134                 disposition = FILE_OPEN_IF;
135         else
136                 disposition = FILE_OPEN;
137
138         if (oplockEnabled)
139                 oplock = REQ_OPLOCK;
140         else
141                 oplock = FALSE;
142
143         /* BB pass O_SYNC flag through on file attributes .. BB */
144
145         /* Also refresh inode by passing in file_info buf returned by SMBOpen 
146            and calling get_inode_info with returned buf (at least 
147            helps non-Unix server case */
148
149         /* BB we can not do this if this is the second open of a file 
150         and the first handle has writebehind data, we might be 
151         able to simply do a filemap_fdatawrite/filemap_fdatawait first */
152         buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
153         if(buf== NULL) {
154                 if (full_path)
155                         kfree(full_path);
156                 FreeXid(xid);
157                 return -ENOMEM;
158         }
159         rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
160                         CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
161         if (rc) {
162                 cFYI(1, ("cifs_open returned 0x%x ", rc));
163                 cFYI(1, ("oplock: %d ", oplock));       
164         } else {
165                 file->private_data =
166                         kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
167                 if (file->private_data) {
168                         memset(file->private_data, 0, sizeof(struct cifsFileInfo));
169                         pCifsFile = (struct cifsFileInfo *) file->private_data;
170                         pCifsFile->netfid = netfid;
171                         pCifsFile->pid = current->tgid;
172                         init_MUTEX(&pCifsFile->fh_sem);
173                         pCifsFile->pfile = file; /* needed for writepage */
174                         pCifsFile->pInode = inode;
175                         pCifsFile->invalidHandle = FALSE;
176                         pCifsFile->closePend     = FALSE;
177                         write_lock(&file->f_owner.lock);
178                         write_lock(&GlobalSMBSeslock);
179                         list_add(&pCifsFile->tlist,&pTcon->openFileList);
180                         pCifsInode = CIFS_I(file->f_dentry->d_inode);
181                         if(pCifsInode) {
182                                 /* want handles we can use to read with first */
183                                 /* in the list so we do not have to walk the */
184                                 /* list to search for one in prepare_write */
185                                 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
186                                         list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
187                                 } else {
188                                         list_add(&pCifsFile->flist,&pCifsInode->openFileList);
189                                 }
190                                 write_unlock(&GlobalSMBSeslock);
191                                 write_unlock(&file->f_owner.lock);
192                                 if(pCifsInode->clientCanCacheRead) {
193                                         /* we have the inode open somewhere else
194                                            no need to discard cache data */
195                                 } else {
196                                         if(buf) {
197                                         /* BB need same check in cifs_create too? */
198
199                                         /* if not oplocked, invalidate inode pages if mtime 
200                                            or file size changed */
201                                                 struct timespec temp;
202                                                 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
203                                                 if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && 
204                                                         (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
205                                                         cFYI(1,("inode unchanged on server"));
206                                                 } else {
207                                                         if(file->f_dentry->d_inode->i_mapping) {
208                                                         /* BB no need to lock inode until after invalidate*/
209                                                         /* since namei code should already have it locked?*/
210                                                                 filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
211                                                                 filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
212                                                         }
213                                                         cFYI(1,("invalidating remote inode since open detected it changed"));
214                                                         invalidate_remote_inode(file->f_dentry->d_inode);
215                                                 }
216                                         }
217                                 }
218                                 if (pTcon->ses->capabilities & CAP_UNIX)
219                                         rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
220                                                 full_path, inode->i_sb,xid);
221                                 else
222                                         rc = cifs_get_inode_info(&file->f_dentry->d_inode,
223                                                 full_path, buf, inode->i_sb,xid);
224
225                                 if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
226                                         pCifsInode->clientCanCacheAll = TRUE;
227                                         pCifsInode->clientCanCacheRead = TRUE;
228                                         cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
229                                 } else if((oplock & 0xF) == OPLOCK_READ)
230                                         pCifsInode->clientCanCacheRead = TRUE;
231                         } else {
232                                 write_unlock(&GlobalSMBSeslock);
233                                 write_unlock(&file->f_owner.lock);
234                         }
235                         if(oplock & CIFS_CREATE_ACTION) {           
236                                 /* time to set mode which we can not set earlier due
237                                  to problems creating new read-only files */
238                                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
239                                         CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
240                                                 (__u64)-1, 
241                                                 (__u64)-1,
242                                                 0 /* dev */,
243                                                 cifs_sb->local_nls);
244                                 else {/* BB implement via Windows security descriptors */
245                         /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
246                         /* in the meantime could set r/o dos attribute when perms are eg:
247                                         mode & 0222 == 0 */
248                                 }
249                         }
250                 }
251         }
252
253         if (buf)
254                 kfree(buf);
255         if (full_path)
256                 kfree(full_path);
257         FreeXid(xid);
258         return rc;
259 }
260
261 /* Try to reaquire byte range locks that were released when session */
262 /* to server was lost */
263 static int cifs_relock_file(struct cifsFileInfo * cifsFile)
264 {
265         int rc = 0;
266
267 /* BB list all locks open on this file and relock */
268
269         return rc;
270 }
271
272 static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
273 {
274         int rc = -EACCES;
275         int xid, oplock;
276         struct cifs_sb_info *cifs_sb;
277         struct cifsTconInfo *pTcon;
278         struct cifsFileInfo *pCifsFile;
279         struct cifsInodeInfo *pCifsInode;
280         char *full_path = NULL;
281         int desiredAccess = 0x20197;
282         int disposition = FILE_OPEN;
283         __u16 netfid;
284
285         if(inode == NULL)
286                 return -EBADF;
287         if (file->private_data) {
288                 pCifsFile = (struct cifsFileInfo *) file->private_data;
289         } else
290                 return -EBADF;
291
292         xid = GetXid();
293         down(&pCifsFile->fh_sem);
294         if(pCifsFile->invalidHandle == FALSE) {
295                 up(&pCifsFile->fh_sem);
296                 FreeXid(xid);
297                 return 0;
298         }
299
300         if(file->f_dentry == NULL) {
301                 up(&pCifsFile->fh_sem);
302                 cFYI(1,("failed file reopen, no valid name if dentry freed"));
303                 FreeXid(xid);
304                 return -EBADF;
305         }
306         cifs_sb = CIFS_SB(inode->i_sb);
307         pTcon = cifs_sb->tcon;
308 /* can not grab rename sem here because various ops, including
309 those that already have the rename sem can end up causing writepage
310 to get called and if the server was down that means we end up here,
311 and we can never tell if the caller already has the rename_sem */
312         full_path = build_path_from_dentry(file->f_dentry);
313         if(full_path == NULL) {
314                 up(&pCifsFile->fh_sem);
315                 FreeXid(xid);
316                 return -ENOMEM;
317         }
318
319         cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
320         if ((file->f_flags & O_ACCMODE) == O_RDONLY)
321                 desiredAccess = GENERIC_READ;
322         else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
323                 desiredAccess = GENERIC_WRITE;
324         else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
325                 /* GENERIC_ALL is too much permission to request */
326                 /* can cause unnecessary access denied on create */
327                 /* desiredAccess = GENERIC_ALL; */
328                 desiredAccess = GENERIC_READ | GENERIC_WRITE;
329         }
330
331         if (oplockEnabled)
332                 oplock = REQ_OPLOCK;
333         else
334                 oplock = FALSE;
335
336         
337         /* Can not refresh inode by passing in file_info buf to be returned
338          by SMBOpen and then calling get_inode_info with returned buf 
339          since file might have write behind data that needs to be flushed 
340          and server version of file size can be stale. If we 
341          knew for sure that inode was not dirty locally we could do this */
342
343 /*      buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
344         if(buf==0) {
345                 up(&pCifsFile->fh_sem);
346                 if (full_path)
347                         kfree(full_path);
348                 FreeXid(xid);
349                 return -ENOMEM;
350         }*/
351         rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
352                                 CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
353         if (rc) {
354                 up(&pCifsFile->fh_sem);
355                 cFYI(1, ("cifs_open returned 0x%x ", rc));
356                 cFYI(1, ("oplock: %d ", oplock));
357         } else {
358                 pCifsFile->netfid = netfid;
359                 pCifsFile->invalidHandle = FALSE;
360                 up(&pCifsFile->fh_sem);
361                 pCifsInode = CIFS_I(inode);
362                 if(pCifsInode) {
363                         if(can_flush) {
364                                 filemap_fdatawrite(inode->i_mapping);
365                                 filemap_fdatawait(inode->i_mapping);
366                         /* temporarily disable caching while we
367                         go to server to get inode info */
368                                 pCifsInode->clientCanCacheAll = FALSE;
369                                 pCifsInode->clientCanCacheRead = FALSE;
370                                 if (pTcon->ses->capabilities & CAP_UNIX)
371                                         rc = cifs_get_inode_info_unix(&inode,
372                                                 full_path, inode->i_sb,xid);
373                                 else
374                                         rc = cifs_get_inode_info(&inode,
375                                                 full_path, NULL, inode->i_sb,xid);
376                         } /* else we are writing out data to server already
377                         and could deadlock if we tried to flush data, and 
378                         since we do not know if we have data that would
379                         invalidate the current end of file on the server
380                         we can not go to the server to get the new
381                         inod info */
382                         if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
383                                 pCifsInode->clientCanCacheAll =  TRUE;
384                                 pCifsInode->clientCanCacheRead = TRUE;
385                                 cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
386                         } else if((oplock & 0xF) == OPLOCK_READ) {
387                                 pCifsInode->clientCanCacheRead = TRUE;
388                                 pCifsInode->clientCanCacheAll =  FALSE;
389                         } else {
390                                 pCifsInode->clientCanCacheRead = FALSE;
391                                 pCifsInode->clientCanCacheAll =  FALSE;
392                         }
393                         cifs_relock_file(pCifsFile);
394                 }
395         }
396
397         if (full_path)
398                 kfree(full_path);
399         FreeXid(xid);
400         return rc;
401 }
402
403 int
404 cifs_close(struct inode *inode, struct file *file)
405 {
406         int rc = 0;
407         int xid;
408         struct cifs_sb_info *cifs_sb;
409         struct cifsTconInfo *pTcon;
410         struct cifsFileInfo *pSMBFile =
411                 (struct cifsFileInfo *) file->private_data;
412
413         xid = GetXid();
414
415         cifs_sb = CIFS_SB(inode->i_sb);
416         pTcon = cifs_sb->tcon;
417         if (pSMBFile) {
418                 pSMBFile->closePend    = TRUE;
419                 write_lock(&file->f_owner.lock);
420                 if(pTcon) {
421                         /* no sense reconnecting to close a file that is
422                                 already closed */
423                         if (pTcon->tidStatus != CifsNeedReconnect) {
424                                 write_unlock(&file->f_owner.lock);
425                                 rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
426                                 write_lock(&file->f_owner.lock);
427                         }
428                 }
429                 list_del(&pSMBFile->flist);
430                 list_del(&pSMBFile->tlist);
431                 write_unlock(&file->f_owner.lock);
432                 if(pSMBFile->search_resume_name)
433                         kfree(pSMBFile->search_resume_name);
434                 kfree(file->private_data);
435                 file->private_data = NULL;
436         } else
437                 rc = -EBADF;
438
439         if(list_empty(&(CIFS_I(inode)->openFileList))) {
440                 cFYI(1,("closing last open instance for inode %p",inode));
441                 /* if the file is not open we do not know if we can cache
442                 info on this inode, much less write behind and read ahead */
443                 CIFS_I(inode)->clientCanCacheRead = FALSE;
444                 CIFS_I(inode)->clientCanCacheAll  = FALSE;
445         }
446         if((rc ==0) && CIFS_I(inode)->write_behind_rc)
447                 rc = CIFS_I(inode)->write_behind_rc;
448         FreeXid(xid);
449         return rc;
450 }
451
452 int
453 cifs_closedir(struct inode *inode, struct file *file)
454 {
455         int rc = 0;
456         int xid;
457         struct cifsFileInfo *pCFileStruct =
458             (struct cifsFileInfo *) file->private_data;
459         char * ptmp;
460
461         cFYI(1, ("Closedir inode = 0x%p with ", inode));
462
463         xid = GetXid();
464
465         if (pCFileStruct) {
466                 struct cifsTconInfo *pTcon;
467                 struct cifs_sb_info * cifs_sb = CIFS_SB(file->f_dentry->d_sb);
468
469                 pTcon = cifs_sb->tcon;
470
471                 cFYI(1, ("Freeing private data in close dir"));
472                 if(pCFileStruct->srch_inf.endOfSearch == FALSE) {
473                         pCFileStruct->invalidHandle = TRUE;
474                         rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
475                         cFYI(1,("Closing uncompleted readdir with rc %d",rc));
476                         /* not much we can do if it fails anywway, ignore rc */
477                         rc = 0;
478                 }
479                 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
480                 if(ptmp) {
481                         cFYI(1,("freeing smb buf in srch struct in closedir")); /* BB removeme BB */
482                         pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
483                         cifs_buf_release(ptmp);
484                 }
485                 ptmp = pCFileStruct->search_resume_name;
486                 if(ptmp) {
487                         cFYI(1,("freeing resume name in closedir")); /* BB removeme BB */
488                         pCFileStruct->search_resume_name = NULL;
489                         kfree(ptmp);
490                 }
491                 kfree(file->private_data);
492                 file->private_data = NULL;
493         }
494         /* BB can we lock the filestruct while this is going on? */
495         FreeXid(xid);
496         return rc;
497 }
498
499 int
500 cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
501 {
502         int rc, xid;
503         __u32 lockType = LOCKING_ANDX_LARGE_FILES;
504         __u32 numLock = 0;
505         __u32 numUnlock = 0;
506         __u64 length;
507         int wait_flag = FALSE;
508         struct cifs_sb_info *cifs_sb;
509         struct cifsTconInfo *pTcon;
510         length = 1 + pfLock->fl_end - pfLock->fl_start;
511
512         rc = -EACCES;
513
514         xid = GetXid();
515
516         cFYI(1,
517              ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
518               cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
519               pfLock->fl_end));
520
521         if (pfLock->fl_flags & FL_POSIX)
522                 cFYI(1, ("Posix "));
523         if (pfLock->fl_flags & FL_FLOCK)
524                 cFYI(1, ("Flock "));
525         if (pfLock->fl_flags & FL_SLEEP) {
526                 cFYI(1, ("Blocking lock "));
527                 wait_flag = TRUE;
528         }
529         if (pfLock->fl_flags & FL_ACCESS)
530                 cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
531         if (pfLock->fl_flags & FL_LEASE)
532                 cFYI(1, ("Lease on file - not implemented yet"));
533         if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
534                 cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
535
536         if (pfLock->fl_type == F_WRLCK) {
537                 cFYI(1, ("F_WRLCK "));
538                 numLock = 1;
539         } else if (pfLock->fl_type == F_UNLCK) {
540                 cFYI(1, ("F_UNLCK "));
541                 numUnlock = 1;
542         } else if (pfLock->fl_type == F_RDLCK) {
543                 cFYI(1, ("F_RDLCK "));
544                 lockType |= LOCKING_ANDX_SHARED_LOCK;
545                 numLock = 1;
546         } else if (pfLock->fl_type == F_EXLCK) {
547                 cFYI(1, ("F_EXLCK "));
548                 numLock = 1;
549         } else if (pfLock->fl_type == F_SHLCK) {
550                 cFYI(1, ("F_SHLCK "));
551                 lockType |= LOCKING_ANDX_SHARED_LOCK;
552                 numLock = 1;
553         } else
554                 cFYI(1, ("Unknown type of lock "));
555
556         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
557         pTcon = cifs_sb->tcon;
558
559         if (file->private_data == NULL) {
560                 FreeXid(xid);
561                 return -EBADF;
562         }
563
564         if (IS_GETLK(cmd)) {
565                 rc = CIFSSMBLock(xid, pTcon,
566                                  ((struct cifsFileInfo *) file->
567                                   private_data)->netfid,
568                                  length,
569                                  pfLock->fl_start, 0, 1, lockType,
570                                  0 /* wait flag */ );
571                 if (rc == 0) {
572                         rc = CIFSSMBLock(xid, pTcon,
573                                          ((struct cifsFileInfo *) file->
574                                           private_data)->netfid,
575                                          length,
576                                          pfLock->fl_start, 1 /* numUnlock */ ,
577                                          0 /* numLock */ , lockType,
578                                          0 /* wait flag */ );
579                         pfLock->fl_type = F_UNLCK;
580                         if (rc != 0)
581                                 cERROR(1,
582                                         ("Error unlocking previously locked range %d during test of lock ",
583                                         rc));
584                         rc = 0;
585
586                 } else {
587                         /* if rc == ERR_SHARING_VIOLATION ? */
588                         rc = 0; /* do not change lock type to unlock since range in use */
589                 }
590
591                 FreeXid(xid);
592                 return rc;
593         }
594
595         rc = CIFSSMBLock(xid, pTcon,
596                          ((struct cifsFileInfo *) file->private_data)->
597                          netfid, length,
598                          pfLock->fl_start, numUnlock, numLock, lockType,
599                          wait_flag);
600         if (rc == 0 && (pfLock->fl_flags & FL_POSIX))
601                 posix_lock_file_wait(file, pfLock);
602         FreeXid(xid);
603         return rc;
604 }
605
606 ssize_t
607 cifs_user_write(struct file * file, const char __user * write_data,
608            size_t write_size, loff_t * poffset)
609 {
610         int rc = 0;
611         unsigned int bytes_written = 0;
612         unsigned int total_written;
613         struct cifs_sb_info *cifs_sb;
614         struct cifsTconInfo *pTcon;
615         int xid, long_op;
616         struct cifsFileInfo * open_file;
617
618         if(file->f_dentry == NULL)
619                 return -EBADF;
620
621         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
622         if(cifs_sb == NULL) {
623                 return -EBADF;
624         }
625         pTcon = cifs_sb->tcon;
626
627         /*cFYI(1,
628            (" write %d bytes to offset %lld of %s", write_size,
629            *poffset, file->f_dentry->d_name.name)); */
630
631         if (file->private_data == NULL) {
632                 return -EBADF;
633         } else {
634                 open_file = (struct cifsFileInfo *) file->private_data;
635         }
636         
637         xid = GetXid();
638         if(file->f_dentry->d_inode == NULL) {
639                 FreeXid(xid);
640                 return -EBADF;
641         }
642
643         if (*poffset > file->f_dentry->d_inode->i_size)
644                 long_op = 2;  /* writes past end of file can take a long time */
645         else
646                 long_op = 1;
647
648         for (total_written = 0; write_size > total_written;
649              total_written += bytes_written) {
650                 rc = -EAGAIN;
651                 while(rc == -EAGAIN) {
652                         if(file->private_data == NULL) {
653                                 /* file has been closed on us */
654                                 FreeXid(xid);
655                         /* if we have gotten here we have written some data
656                         and blocked, and the file has been freed on us
657                         while we blocked so return what we managed to write */
658                                 return total_written;
659                         } 
660                         if(open_file->closePend) {
661                                 FreeXid(xid);
662                                 if(total_written)
663                                         return total_written;
664                                 else
665                                         return -EBADF;
666                         }
667                         if (open_file->invalidHandle) {
668                                 if((file->f_dentry == NULL) ||
669                                    (file->f_dentry->d_inode == NULL)) {
670                                         FreeXid(xid);
671                                         return total_written;
672                                 }
673                                 /* we could deadlock if we called
674                                  filemap_fdatawait from here so tell
675                                 reopen_file not to flush data to server now */
676                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
677                                         file,FALSE);
678                                 if(rc != 0)
679                                         break;
680                         }
681
682                         rc = CIFSSMBWrite(xid, pTcon,
683                                   open_file->netfid,
684                                   write_size - total_written, *poffset,
685                                   &bytes_written,
686                                   NULL, write_data + total_written, long_op);
687                 }
688                 if (rc || (bytes_written == 0)) {
689                         if (total_written)
690                                 break;
691                         else {
692                                 FreeXid(xid);
693                                 return rc;
694                         }
695                 } else
696                         *poffset += bytes_written;
697                 long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
698         }
699
700 #ifdef CONFIG_CIFS_STATS
701         if(total_written > 0) {
702                 atomic_inc(&pTcon->num_writes);
703                 spin_lock(&pTcon->stat_lock);
704                 pTcon->bytes_written += total_written;
705                 spin_unlock(&pTcon->stat_lock);
706         }
707 #endif          
708
709         /* since the write may have blocked check these pointers again */
710         if(file->f_dentry) {
711                 if(file->f_dentry->d_inode) {
712                         file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
713                                 CURRENT_TIME;
714                         if (total_written > 0) {
715                                 if (*poffset > file->f_dentry->d_inode->i_size)
716                                         i_size_write(file->f_dentry->d_inode, *poffset);
717                         }
718                         mark_inode_dirty_sync(file->f_dentry->d_inode);
719                 }
720         }
721         FreeXid(xid);
722         return total_written;
723 }
724
725 static ssize_t
726 cifs_write(struct file * file, const char *write_data,
727            size_t write_size, loff_t * poffset)
728 {
729         int rc = 0;
730         unsigned int bytes_written = 0;
731         unsigned int total_written;
732         struct cifs_sb_info *cifs_sb;
733         struct cifsTconInfo *pTcon;
734         int xid, long_op;
735         struct cifsFileInfo * open_file;
736
737         if(file->f_dentry == NULL)
738                 return -EBADF;
739
740         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
741         if(cifs_sb == NULL) {
742                 return -EBADF;
743         }
744         pTcon = cifs_sb->tcon;
745
746         /*cFYI(1,
747            (" write %d bytes to offset %lld of %s", write_size,
748            *poffset, file->f_dentry->d_name.name)); */
749
750         if (file->private_data == NULL) {
751                 return -EBADF;
752         } else {
753                 open_file = (struct cifsFileInfo *) file->private_data;
754         }
755         
756         xid = GetXid();
757         if(file->f_dentry->d_inode == NULL) {
758                 FreeXid(xid);
759                 return -EBADF;
760         }
761
762         if (*poffset > file->f_dentry->d_inode->i_size)
763                 long_op = 2;  /* writes past end of file can take a long time */
764         else
765                 long_op = 1;
766
767         for (total_written = 0; write_size > total_written;
768              total_written += bytes_written) {
769                 rc = -EAGAIN;
770                 while(rc == -EAGAIN) {
771                         if(file->private_data == NULL) {
772                                 /* file has been closed on us */
773                                 FreeXid(xid);
774                         /* if we have gotten here we have written some data
775                         and blocked, and the file has been freed on us
776                         while we blocked so return what we managed to write */
777                                 return total_written;
778                         } 
779                         if(open_file->closePend) {
780                                 FreeXid(xid);
781                                 if(total_written)
782                                         return total_written;
783                                 else
784                                         return -EBADF;
785                         }
786                         if (open_file->invalidHandle) {
787                                 if((file->f_dentry == NULL) ||
788                                    (file->f_dentry->d_inode == NULL)) {
789                                         FreeXid(xid);
790                                         return total_written;
791                                 }
792                                 /* we could deadlock if we called
793                                  filemap_fdatawait from here so tell
794                                 reopen_file not to flush data to server now */
795                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
796                                         file,FALSE);
797                                 if(rc != 0)
798                                         break;
799                         }
800
801                         rc = CIFSSMBWrite(xid, pTcon,
802                                   open_file->netfid,
803                                   write_size - total_written, *poffset,
804                                   &bytes_written,
805                                   write_data + total_written, NULL, long_op);
806                 }
807                 if (rc || (bytes_written == 0)) {
808                         if (total_written)
809                                 break;
810                         else {
811                                 FreeXid(xid);
812                                 return rc;
813                         }
814                 } else
815                         *poffset += bytes_written;
816                 long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
817         }
818
819 #ifdef CONFIG_CIFS_STATS
820         if(total_written > 0) {
821                 atomic_inc(&pTcon->num_writes);
822                 spin_lock(&pTcon->stat_lock);
823                 pTcon->bytes_written += total_written;
824                 spin_unlock(&pTcon->stat_lock);
825         }
826 #endif          
827
828         /* since the write may have blocked check these pointers again */
829         if(file->f_dentry) {
830                 if(file->f_dentry->d_inode) {
831                         file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
832                                 CURRENT_TIME;
833                         if (total_written > 0) {
834                                 if (*poffset > file->f_dentry->d_inode->i_size)
835                                         i_size_write(file->f_dentry->d_inode, *poffset);
836                         }
837                         mark_inode_dirty_sync(file->f_dentry->d_inode);
838                 }
839         }
840         FreeXid(xid);
841         return total_written;
842 }
843
844 static int
845 cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
846 {
847         struct address_space *mapping = page->mapping;
848         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
849         char * write_data;
850         int rc = -EFAULT;
851         int bytes_written = 0;
852         struct cifs_sb_info *cifs_sb;
853         struct cifsTconInfo *pTcon;
854         struct inode *inode;
855         struct cifsInodeInfo *cifsInode;
856         struct cifsFileInfo *open_file = NULL;
857         struct list_head *tmp;
858         struct list_head *tmp1;
859
860         if (!mapping) {
861                 return -EFAULT;
862         } else if(!mapping->host) {
863                 return -EFAULT;
864         }
865
866         inode = page->mapping->host;
867         cifs_sb = CIFS_SB(inode->i_sb);
868         pTcon = cifs_sb->tcon;
869
870         offset += (loff_t)from;
871         write_data = kmap(page);
872         write_data += from;
873
874         if((to > PAGE_CACHE_SIZE) || (from > to)) {
875                 kunmap(page);
876                 return -EIO;
877         }
878
879         /* racing with truncate? */
880         if(offset > mapping->host->i_size) {
881                 kunmap(page);
882                 return 0; /* don't care */
883         }
884
885         /* check to make sure that we are not extending the file */
886         if(mapping->host->i_size - offset < (loff_t)to)
887                 to = (unsigned)(mapping->host->i_size - offset); 
888                 
889
890         cifsInode = CIFS_I(mapping->host);
891         read_lock(&GlobalSMBSeslock); 
892         /* BB we should start at the end */
893         list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
894                 open_file = list_entry(tmp,struct cifsFileInfo, flist);
895                 if(open_file->closePend)
896                         continue;
897                 /* We check if file is open for writing first */
898                 if((open_file->pfile) && 
899                    ((open_file->pfile->f_flags & O_RDWR) || 
900                         (open_file->pfile->f_flags & O_WRONLY))) {
901                         read_unlock(&GlobalSMBSeslock);
902                         bytes_written = cifs_write(open_file->pfile, write_data,
903                                         to-from, &offset);
904                         read_lock(&GlobalSMBSeslock);
905                 /* Does mm or vfs already set times? */
906                         inode->i_atime = inode->i_mtime = CURRENT_TIME;
907                         if ((bytes_written > 0) && (offset)) {
908                                 rc = 0;
909                         } else if(bytes_written < 0) {
910                                 if(rc == -EBADF) {
911                                 /* have seen a case in which
912                                 kernel seemed to have closed/freed a file
913                                 even with writes active so we might as well
914                                 see if there are other file structs to try
915                                 for the same inode before giving up */
916                                         continue;
917                                 } else
918                                         rc = bytes_written;
919                         }
920                         break;  /* now that we found a valid file handle
921                                 and tried to write to it we are done, no
922                                 sense continuing to loop looking for another */
923                 }
924                 if(tmp->next == NULL) {
925                         cFYI(1,("File instance %p removed",tmp));
926                         break;
927                 }
928         }
929         read_unlock(&GlobalSMBSeslock);
930         if(open_file == NULL) {
931                 cFYI(1,("No writeable filehandles for inode"));
932                 rc = -EIO;
933         }
934
935         kunmap(page);
936         return rc;
937 }
938
939 #if 0
940 static int
941 cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
942 {
943         int rc = -EFAULT;
944         int xid;
945
946         xid = GetXid();
947 /* call 16K write then Setpageuptodate */
948         FreeXid(xid);
949         return rc;
950 }
951 #endif
952
953 static int
954 cifs_writepage(struct page* page, struct writeback_control *wbc)
955 {
956         int rc = -EFAULT;
957         int xid;
958
959         xid = GetXid();
960 /* BB add check for wbc flags */
961         page_cache_get(page);
962         if (!PageUptodate(page)) {
963                 cFYI(1,("ppw - page not up to date"));
964         }
965         
966         rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
967         SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
968         unlock_page(page);
969         page_cache_release(page);       
970         FreeXid(xid);
971         return rc;
972 }
973
974 static int
975 cifs_commit_write(struct file *file, struct page *page, unsigned offset,
976                   unsigned to)
977 {
978         int xid;
979         int rc = 0;
980         struct inode *inode = page->mapping->host;
981         loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
982         char * page_data;
983
984         xid = GetXid();
985         cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
986         if (position > inode->i_size){
987                 i_size_write(inode, position);
988                 /*if (file->private_data == NULL) {
989                         rc = -EBADF;
990                 } else {
991                         open_file = (struct cifsFileInfo *)file->private_data;
992                         cifs_sb = CIFS_SB(inode->i_sb);
993                         rc = -EAGAIN;
994                         while(rc == -EAGAIN) {
995                                 if((open_file->invalidHandle) && 
996                                   (!open_file->closePend)) {
997                                         rc = cifs_reopen_file(file->f_dentry->d_inode,file);
998                                         if(rc != 0)
999                                                 break;
1000                                 }
1001                                 if(!open_file->closePend) {
1002                                         rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, 
1003                                                 position, open_file->netfid,
1004                                                 open_file->pid,FALSE);
1005                                 } else {
1006                                         rc = -EBADF;
1007                                         break;
1008                                 }
1009                         }
1010                         cFYI(1,(" SetEOF (commit write) rc = %d",rc));
1011                 }*/
1012         }
1013         if (!PageUptodate(page)) {
1014                 position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1015                 /* can not rely on (or let) writepage write this data */
1016                 if(to < offset) {
1017                         cFYI(1,("Illegal offsets, can not copy from %d to %d",
1018                                 offset,to));
1019                         FreeXid(xid);
1020                         return rc;
1021                 }
1022                 /* this is probably better than directly calling 
1023                 partialpage_write since in this function
1024                 the file handle is known which we might as well
1025                 leverage */
1026                 /* BB check if anything else missing out of ppw */
1027                 /* such as updating last write time */
1028                 page_data = kmap(page);
1029                 rc = cifs_write(file, page_data+offset,to-offset,
1030                                         &position);
1031                 if(rc > 0)
1032                         rc = 0;
1033                 /* else if rc < 0 should we set writebehind rc? */
1034                 kunmap(page);
1035         } else {        
1036                 set_page_dirty(page);
1037         }
1038
1039         FreeXid(xid);
1040         return rc;
1041 }
1042
1043 int
1044 cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1045 {
1046         int xid;
1047         int rc = 0;
1048         struct inode * inode = file->f_dentry->d_inode;
1049
1050         xid = GetXid();
1051
1052         cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
1053                 dentry->d_name.name, datasync));
1054         
1055         rc = filemap_fdatawrite(inode->i_mapping);
1056         if(rc == 0)
1057                 CIFS_I(inode)->write_behind_rc = 0;
1058         FreeXid(xid);
1059         return rc;
1060 }
1061
1062 /* static int
1063 cifs_sync_page(struct page *page)
1064 {
1065         struct address_space *mapping;
1066         struct inode *inode;
1067         unsigned long index = page->index;
1068         unsigned int rpages = 0;
1069         int rc = 0;
1070
1071         cFYI(1,("sync page %p",page));
1072         mapping = page->mapping;
1073         if (!mapping)
1074                 return 0;
1075         inode = mapping->host;
1076         if (!inode)
1077                 return 0;*/
1078
1079 /*      fill in rpages then 
1080     result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
1081
1082 /*   cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
1083
1084         if (rc < 0)
1085                 return rc;
1086         return 0;
1087 } */
1088
1089 /*
1090  * As file closes, flush all cached write data for this inode checking
1091  * for write behind errors.
1092  *
1093  */
1094 int cifs_flush(struct file *file)
1095 {
1096         struct inode * inode = file->f_dentry->d_inode;
1097         int rc = 0;
1098
1099         /* Rather than do the steps manually: */
1100         /* lock the inode for writing */
1101         /* loop through pages looking for write behind data (dirty pages) */
1102         /* coalesce into contiguous 16K (or smaller) chunks to write to server */
1103         /* send to server (prefer in parallel) */
1104         /* deal with writebehind errors */
1105         /* unlock inode for writing */
1106         /* filemapfdatawrite appears easier for the time being */
1107
1108         rc = filemap_fdatawrite(inode->i_mapping);
1109         if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
1110                 CIFS_I(inode)->write_behind_rc = 0;
1111                 
1112         cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
1113
1114         return rc;
1115 }
1116
1117
1118 ssize_t
1119 cifs_user_read(struct file * file, char __user *read_data, size_t read_size,
1120           loff_t * poffset)
1121 {
1122         int rc = -EACCES;
1123         unsigned int bytes_read = 0;
1124         unsigned int total_read = 0;
1125         unsigned int current_read_size;
1126         struct cifs_sb_info *cifs_sb;
1127         struct cifsTconInfo *pTcon;
1128         int xid;
1129         struct cifsFileInfo * open_file;
1130         char * smb_read_data;
1131         char __user * current_offset;
1132         struct smb_com_read_rsp * pSMBr;
1133
1134         xid = GetXid();
1135         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1136         pTcon = cifs_sb->tcon;
1137
1138         if (file->private_data == NULL) {
1139                 FreeXid(xid);
1140                 return -EBADF;
1141         }
1142         open_file = (struct cifsFileInfo *)file->private_data;
1143
1144         if((file->f_flags & O_ACCMODE) == O_WRONLY) {
1145                 cFYI(1,("attempting read on write only file instance"));
1146         }
1147
1148         for (total_read = 0,current_offset=read_data; read_size > total_read;
1149                                 total_read += bytes_read,current_offset+=bytes_read) {
1150                 current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
1151                 rc = -EAGAIN;
1152                 smb_read_data = NULL;
1153                 while(rc == -EAGAIN) {
1154                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1155                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
1156                                         file,TRUE);
1157                                 if(rc != 0)
1158                                         break;
1159                         }
1160
1161                         rc = CIFSSMBRead(xid, pTcon,
1162                                  open_file->netfid,
1163                                  current_read_size, *poffset,
1164                                  &bytes_read, &smb_read_data);
1165
1166                         pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1167                         copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/
1168                                 + le16_to_cpu(pSMBr->DataOffset), bytes_read);
1169                         if(smb_read_data) {
1170                                 cifs_buf_release(smb_read_data);
1171                                 smb_read_data = NULL;
1172                         }
1173                 }
1174                 if (rc || (bytes_read == 0)) {
1175                         if (total_read) {
1176                                 break;
1177                         } else {
1178                                 FreeXid(xid);
1179                                 return rc;
1180                         }
1181                 } else {
1182 #ifdef CONFIG_CIFS_STATS
1183                         atomic_inc(&pTcon->num_reads);
1184                         spin_lock(&pTcon->stat_lock);
1185                         pTcon->bytes_read += total_read;
1186                         spin_unlock(&pTcon->stat_lock);
1187 #endif
1188                         *poffset += bytes_read;
1189                 }
1190         }
1191         FreeXid(xid);
1192         return total_read;
1193 }
1194
1195 static ssize_t
1196 cifs_read(struct file * file, char *read_data, size_t read_size,
1197           loff_t * poffset)
1198 {
1199         int rc = -EACCES;
1200         unsigned int bytes_read = 0;
1201         unsigned int total_read;
1202         unsigned int current_read_size;
1203         struct cifs_sb_info *cifs_sb;
1204         struct cifsTconInfo *pTcon;
1205         int xid;
1206         char * current_offset;
1207         struct cifsFileInfo * open_file;
1208
1209         xid = GetXid();
1210         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1211         pTcon = cifs_sb->tcon;
1212
1213         if (file->private_data == NULL) {
1214                 FreeXid(xid);
1215                 return -EBADF;
1216         }
1217         open_file = (struct cifsFileInfo *)file->private_data;
1218
1219         if((file->f_flags & O_ACCMODE) == O_WRONLY) {
1220                 cFYI(1,("attempting read on write only file instance"));
1221         }
1222
1223         for (total_read = 0,current_offset=read_data; read_size > total_read;
1224                                 total_read += bytes_read,current_offset+=bytes_read) {
1225                 current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
1226                 rc = -EAGAIN;
1227                 while(rc == -EAGAIN) {
1228                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1229                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
1230                                         file,TRUE);
1231                                 if(rc != 0)
1232                                         break;
1233                         }
1234
1235                         rc = CIFSSMBRead(xid, pTcon,
1236                                  open_file->netfid,
1237                                  current_read_size, *poffset,
1238                                  &bytes_read, &current_offset);
1239                 }
1240                 if (rc || (bytes_read == 0)) {
1241                         if (total_read) {
1242                                 break;
1243                         } else {
1244                                 FreeXid(xid);
1245                                 return rc;
1246                         }
1247                 } else {
1248 #ifdef CONFIG_CIFS_STATS
1249                         atomic_inc(&pTcon->num_reads);
1250                         spin_lock(&pTcon->stat_lock);
1251                         pTcon->bytes_read += total_read;
1252                         spin_unlock(&pTcon->stat_lock);
1253 #endif
1254                         *poffset += bytes_read;
1255                 }
1256         }
1257         FreeXid(xid);
1258         return total_read;
1259 }
1260
1261 int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
1262 {
1263         struct dentry * dentry = file->f_dentry;
1264         int     rc, xid;
1265
1266 #ifdef CIFS_EXPERIMENTAL   /* BB fixme reenable when cifs_read_wrapper fixed */
1267         if(dentry->d_sb) {
1268                 struct cifs_sb_info *cifs_sb;
1269                 cifs_sb = CIFS_SB(sb);
1270                 if(cifs_sb != NULL) {
1271                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
1272                                 return -ENODEV
1273                 }
1274         }
1275 #endif /* CIFS_EXPERIMENTAL */
1276
1277         xid = GetXid();
1278         rc = cifs_revalidate(dentry);
1279         if (rc) {
1280                 cFYI(1,("Validation prior to mmap failed, error=%d", rc));
1281                 FreeXid(xid);
1282                 return rc;
1283         }
1284         rc = generic_file_mmap(file, vma);
1285         FreeXid(xid);
1286         return rc;
1287 }
1288
1289 static void cifs_copy_cache_pages(struct address_space *mapping, 
1290                 struct list_head *pages, int bytes_read, 
1291                 char *data,struct pagevec * plru_pvec)
1292 {
1293         struct page *page;
1294         char * target;
1295
1296         while (bytes_read > 0) {
1297                 if(list_empty(pages))
1298                         break;
1299
1300                 page = list_entry(pages->prev, struct page, lru);
1301                 list_del(&page->lru);
1302
1303                 if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
1304                         page_cache_release(page);
1305                         cFYI(1,("Add page cache failed"));
1306                         continue;
1307                 }
1308
1309                 target = kmap_atomic(page,KM_USER0);
1310
1311                 if(PAGE_CACHE_SIZE > bytes_read) {
1312                         memcpy(target,data,bytes_read);
1313                         /* zero the tail end of this partial page */
1314                         memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
1315                         bytes_read = 0;
1316                 } else {
1317                         memcpy(target,data,PAGE_CACHE_SIZE);
1318                         bytes_read -= PAGE_CACHE_SIZE;
1319                 }
1320                 kunmap_atomic(target,KM_USER0);
1321
1322                 flush_dcache_page(page);
1323                 SetPageUptodate(page);
1324                 unlock_page(page);
1325                 if (!pagevec_add(plru_pvec, page))
1326                         __pagevec_lru_add(plru_pvec);
1327                 data += PAGE_CACHE_SIZE;
1328         }
1329         return;
1330 }
1331
1332
1333 static int
1334 cifs_readpages(struct file *file, struct address_space *mapping,
1335                 struct list_head *page_list, unsigned num_pages)
1336 {
1337         int rc = -EACCES;
1338         int xid;
1339         loff_t offset;
1340         struct page * page;
1341         struct cifs_sb_info *cifs_sb;
1342         struct cifsTconInfo *pTcon;
1343         int bytes_read = 0;
1344         unsigned int read_size,i;
1345         char * smb_read_data = NULL;
1346         struct smb_com_read_rsp * pSMBr;
1347         struct pagevec lru_pvec;
1348         struct cifsFileInfo * open_file;
1349
1350         xid = GetXid();
1351         if (file->private_data == NULL) {
1352                 FreeXid(xid);
1353                 return -EBADF;
1354         }
1355         open_file = (struct cifsFileInfo *)file->private_data;
1356         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1357         pTcon = cifs_sb->tcon;
1358
1359         pagevec_init(&lru_pvec, 0);
1360
1361         for(i = 0;i<num_pages;) {
1362                 unsigned contig_pages;
1363                 struct page * tmp_page;
1364                 unsigned long expected_index;
1365
1366                 if(list_empty(page_list)) {
1367                         break;
1368                 }
1369                 page = list_entry(page_list->prev, struct page, lru);
1370                 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1371
1372                 /* count adjacent pages that we will read into */
1373                 contig_pages = 0;
1374                 expected_index = list_entry(page_list->prev,struct page,lru)->index;
1375                 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1376                         if(tmp_page->index == expected_index) {
1377                                 contig_pages++;
1378                                 expected_index++;
1379                         } else {
1380                                 break; 
1381                         }
1382                 }
1383                 if(contig_pages + i >  num_pages) {
1384                         contig_pages = num_pages - i;
1385                 }
1386
1387                 /* for reads over a certain size could initiate async read ahead */
1388
1389                 read_size = contig_pages * PAGE_CACHE_SIZE;
1390                 /* Read size needs to be in multiples of one page */
1391                 read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
1392
1393                 rc = -EAGAIN;
1394                 while(rc == -EAGAIN) {
1395                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1396                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
1397                                         file, TRUE);
1398                                 if(rc != 0)
1399                                         break;
1400                         }
1401
1402                         rc = CIFSSMBRead(xid, pTcon,
1403                                 open_file->netfid,
1404                                 read_size, offset,
1405                                 &bytes_read, &smb_read_data);
1406                         /* BB need to check return code here */
1407                         if(rc== -EAGAIN) {
1408                                 if(smb_read_data) {
1409                                         cifs_buf_release(smb_read_data);
1410                                         smb_read_data = NULL;
1411                                 }
1412                         }
1413                 }
1414                 if ((rc < 0) || (smb_read_data == NULL)) {
1415                         cFYI(1,("Read error in readpages: %d",rc));
1416                         /* clean up remaing pages off list */
1417                         while (!list_empty(page_list) && (i < num_pages)) {
1418                                 page = list_entry(page_list->prev, struct page, lru);
1419                                 list_del(&page->lru);
1420                                 page_cache_release(page);
1421                         }
1422                         break;
1423                 } else if (bytes_read > 0) {
1424                         pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1425                         cifs_copy_cache_pages(mapping, page_list, bytes_read,
1426                                 smb_read_data + 4 /* RFC1001 hdr */ +
1427                                 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1428
1429                         i +=  bytes_read >> PAGE_CACHE_SHIFT;
1430 #ifdef CONFIG_CIFS_STATS
1431                         atomic_inc(&pTcon->num_reads);
1432                         spin_lock(&pTcon->stat_lock);
1433                         pTcon->bytes_read += bytes_read;
1434                         spin_unlock(&pTcon->stat_lock);
1435 #endif
1436                         if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1437                                 i++; /* account for partial page */
1438
1439                                 /* server copy of file can have smaller size than client */
1440                                 /* BB do we need to verify this common case ? this case is ok - 
1441                                 if we are at server EOF we will hit it on next read */
1442
1443                         /* while(!list_empty(page_list) && (i < num_pages)) {
1444                                         page = list_entry(page_list->prev,struct page, list);
1445                                         list_del(&page->list);
1446                                         page_cache_release(page);
1447                                 }
1448                                 break; */
1449                         }
1450                 } else {
1451                         cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); 
1452                         /* BB turn off caching and do new lookup on file size at server? */
1453                         while (!list_empty(page_list) && (i < num_pages)) {
1454                                 page = list_entry(page_list->prev, struct page, lru);
1455                                 list_del(&page->lru);
1456                                 page_cache_release(page); /* BB removeme - replace with zero of page? */
1457                         }
1458                         break;
1459                 }
1460                 if(smb_read_data) {
1461                         cifs_buf_release(smb_read_data);
1462                         smb_read_data = NULL;
1463                 }
1464                 bytes_read = 0;
1465         }
1466
1467         pagevec_lru_add(&lru_pvec);
1468
1469 /* need to free smb_read_data buf before exit */
1470         if(smb_read_data) {
1471                 cifs_buf_release(smb_read_data);
1472                 smb_read_data = NULL;
1473         } 
1474
1475         FreeXid(xid);
1476         return rc;
1477 }
1478
1479 static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
1480 {
1481         char * read_data;
1482         int rc;
1483
1484         page_cache_get(page);
1485         read_data = kmap(page);
1486         /* for reads over a certain size could initiate async read ahead */
1487                                                                                                                            
1488         rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1489                                                                                                                            
1490         if (rc < 0)
1491                 goto io_error;
1492         else {
1493                 cFYI(1,("Bytes read %d ",rc));
1494         }
1495                                                                                                                            
1496         file->f_dentry->d_inode->i_atime = CURRENT_TIME;
1497                                                                                                                            
1498         if(PAGE_CACHE_SIZE > rc) {
1499                 memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
1500         }
1501         flush_dcache_page(page);
1502         SetPageUptodate(page);
1503         rc = 0;
1504                                                                                                                            
1505 io_error:
1506         kunmap(page);
1507         page_cache_release(page);
1508         return rc;
1509 }
1510
1511 static int
1512 cifs_readpage(struct file *file, struct page *page)
1513 {
1514         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1515         int rc = -EACCES;
1516         int xid;
1517
1518         xid = GetXid();
1519
1520         if (file->private_data == NULL) {
1521                 FreeXid(xid);
1522                 return -EBADF;
1523         }
1524
1525         cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
1526
1527         rc = cifs_readpage_worker(file,page,&offset);
1528
1529         unlock_page(page);
1530
1531         FreeXid(xid);
1532         return rc;
1533 }
1534
1535 /* We do not want to update the file size from server for inodes
1536    open for write - to avoid races with writepage extending
1537    the file - in the future we could consider allowing
1538    refreshing the inode only on increases in the file size 
1539    but this is tricky to do without racing with writebehind
1540    page caching in the current Linux kernel design */
1541    
1542 int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
1543 {
1544         struct list_head *tmp;
1545         struct list_head *tmp1;
1546         struct cifsFileInfo *open_file = NULL;
1547         int rc = TRUE;
1548
1549         if(cifsInode == NULL)
1550                 return rc;
1551
1552         read_lock(&GlobalSMBSeslock); 
1553         list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
1554                 open_file = list_entry(tmp,struct cifsFileInfo, flist);
1555                 if(open_file == NULL)
1556                         break;
1557                 if(open_file->closePend)
1558                         continue;
1559         /* We check if file is open for writing,   
1560         BB we could supplement this with a check to see if file size
1561         changes have been flushed to server - ie inode metadata dirty */
1562                 if((open_file->pfile) && 
1563            ((open_file->pfile->f_flags & O_RDWR) || 
1564                 (open_file->pfile->f_flags & O_WRONLY))) {
1565                          rc = FALSE;
1566                          break;
1567                 }
1568                 if(tmp->next == NULL) {
1569                         cFYI(1,("File instance %p removed",tmp));
1570                         break;
1571                 }
1572         }
1573         read_unlock(&GlobalSMBSeslock);
1574         return rc;
1575 }
1576
1577
1578 void
1579 fill_in_inode(struct inode *tmp_inode,
1580               FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
1581 {
1582         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1583         struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1584         __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
1585         __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
1586         __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
1587
1588         cifsInfo->cifsAttrs = attr;
1589         cifsInfo->time = jiffies;
1590
1591         /* Linux can not store file creation time unfortunately so ignore it */
1592         tmp_inode->i_atime =
1593             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1594         tmp_inode->i_mtime =
1595             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
1596         tmp_inode->i_ctime =
1597             cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
1598         /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
1599         /* 2767 perms - indicate mandatory locking */
1600                 /* BB fill in uid and gid here? with help from winbind? 
1601                         or retrieve from NTFS stream extended attribute */
1602         if(atomic_read(&cifsInfo->inUse) == 0) {
1603                 tmp_inode->i_uid = cifs_sb->mnt_uid;
1604                 tmp_inode->i_gid = cifs_sb->mnt_gid;
1605                 /* set default mode. will override for dirs below */
1606                 tmp_inode->i_mode = cifs_sb->mnt_file_mode;
1607         }
1608
1609         cFYI(0,
1610              ("CIFS FFIRST: Attributes came in as 0x%x",
1611               attr));
1612         if (attr & ATTR_DIRECTORY) {
1613                 *pobject_type = DT_DIR;
1614                 /* override default perms since we do not lock dirs */
1615                 if(atomic_read(&cifsInfo->inUse) == 0) {
1616                         tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
1617                 }
1618                 tmp_inode->i_mode |= S_IFDIR;
1619 /* we no longer mark these because we could not follow them */
1620 /*        } else if (attr & ATTR_REPARSE) {
1621                 *pobject_type = DT_LNK;
1622                 tmp_inode->i_mode |= S_IFLNK;*/
1623         } else {
1624                 *pobject_type = DT_REG;
1625                 tmp_inode->i_mode |= S_IFREG;
1626                 if(attr & ATTR_READONLY)
1627                         tmp_inode->i_mode &= ~(S_IWUGO);
1628         }/* could add code here - to validate if device or weird share type? */
1629
1630         /* can not fill in nlink here as in qpathinfo version and Unx search */
1631         if(atomic_read(&cifsInfo->inUse) == 0) {
1632                 atomic_set(&cifsInfo->inUse,1);
1633         }
1634
1635         if(is_size_safe_to_change(cifsInfo)) {
1636                 /* can not safely change the file size here if the 
1637                 client is writing to it due to potential races */
1638                 i_size_write(tmp_inode,end_of_file);
1639
1640         /* 512 bytes (2**9) is the fake blocksize that must be used */
1641         /* for this calculation, even though the reported blocksize is larger */
1642                 tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
1643         }
1644
1645         if (allocation_size < end_of_file)
1646                 cFYI(1, ("Possible sparse file: allocation size less than end of file "));
1647         cFYI(1,
1648              ("File Size %ld and blocks %ld and blocksize %ld",
1649               (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
1650               tmp_inode->i_blksize));
1651         if (S_ISREG(tmp_inode->i_mode)) {
1652                 cFYI(1, (" File inode "));
1653                 tmp_inode->i_op = &cifs_file_inode_ops;
1654                 tmp_inode->i_fop = &cifs_file_ops;
1655                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1656         } else if (S_ISDIR(tmp_inode->i_mode)) {
1657                 cFYI(1, (" Directory inode"));
1658                 tmp_inode->i_op = &cifs_dir_inode_ops;
1659                 tmp_inode->i_fop = &cifs_dir_ops;
1660         } else if (S_ISLNK(tmp_inode->i_mode)) {
1661                 cFYI(1, (" Symbolic Link inode "));
1662                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1663         } else {
1664                 cFYI(1, (" Init special inode "));
1665                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1666                                    tmp_inode->i_rdev);
1667         }
1668 }
1669
1670 void
1671 unix_fill_in_inode(struct inode *tmp_inode,
1672                    FILE_UNIX_INFO * pfindData, int *pobject_type)
1673 {
1674         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1675         __u32 type = le32_to_cpu(pfindData->Type);
1676         __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
1677         __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
1678         cifsInfo->time = jiffies;
1679         atomic_inc(&cifsInfo->inUse);
1680
1681         tmp_inode->i_atime =
1682             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1683         tmp_inode->i_mtime =
1684             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
1685         tmp_inode->i_ctime =
1686             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
1687
1688         tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
1689         if (type == UNIX_FILE) {
1690                 *pobject_type = DT_REG;
1691                 tmp_inode->i_mode |= S_IFREG;
1692         } else if (type == UNIX_SYMLINK) {
1693                 *pobject_type = DT_LNK;
1694                 tmp_inode->i_mode |= S_IFLNK;
1695         } else if (type == UNIX_DIR) {
1696                 *pobject_type = DT_DIR;
1697                 tmp_inode->i_mode |= S_IFDIR;
1698         } else if (type == UNIX_CHARDEV) {
1699                 *pobject_type = DT_CHR;
1700                 tmp_inode->i_mode |= S_IFCHR;
1701                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
1702                                 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1703         } else if (type == UNIX_BLOCKDEV) {
1704                 *pobject_type = DT_BLK;
1705                 tmp_inode->i_mode |= S_IFBLK;
1706                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
1707                                 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1708         } else if (type == UNIX_FIFO) {
1709                 *pobject_type = DT_FIFO;
1710                 tmp_inode->i_mode |= S_IFIFO;
1711         } else if (type == UNIX_SOCKET) {
1712                 *pobject_type = DT_SOCK;
1713                 tmp_inode->i_mode |= S_IFSOCK;
1714         }
1715
1716         tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
1717         tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
1718         tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
1719
1720
1721         if(is_size_safe_to_change(cifsInfo)) {
1722                 /* can not safely change the file size here if the 
1723                 client is writing to it due to potential races */
1724                 i_size_write(tmp_inode,end_of_file);
1725
1726         /* 512 bytes (2**9) is the fake blocksize that must be used */
1727         /* for this calculation, not the real blocksize */
1728                 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
1729         }
1730
1731         if (S_ISREG(tmp_inode->i_mode)) {
1732                 cFYI(1, ("File inode"));
1733                 tmp_inode->i_op = &cifs_file_inode_ops;
1734                 tmp_inode->i_fop = &cifs_file_ops;
1735                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1736         } else if (S_ISDIR(tmp_inode->i_mode)) {
1737                 cFYI(1, ("Directory inode"));
1738                 tmp_inode->i_op = &cifs_dir_inode_ops;
1739                 tmp_inode->i_fop = &cifs_dir_ops;
1740         } else if (S_ISLNK(tmp_inode->i_mode)) {
1741                 cFYI(1, ("Symbolic Link inode"));
1742                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1743 /* tmp_inode->i_fop = *//* do not need to set to anything */
1744         } else {
1745                 cFYI(1, ("Special inode")); 
1746                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1747                                    tmp_inode->i_rdev);
1748         }
1749 }
1750
1751 /* Returns one if new inode created (which therefore needs to be hashed) */
1752 /* Might check in the future if inode number changed so we can rehash inode */
1753 int
1754 construct_dentry(struct qstr *qstring, struct file *file,
1755                  struct inode **ptmp_inode, struct dentry **pnew_dentry)
1756 {
1757         struct dentry *tmp_dentry;
1758         struct cifs_sb_info *cifs_sb;
1759         struct cifsTconInfo *pTcon;
1760         int rc = 0;
1761
1762         cFYI(1, ("For %s ", qstring->name));
1763         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1764         pTcon = cifs_sb->tcon;
1765
1766         qstring->hash = full_name_hash(qstring->name, qstring->len);
1767         tmp_dentry = d_lookup(file->f_dentry, qstring);
1768         if (tmp_dentry) {
1769                 cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
1770                 *ptmp_inode = tmp_dentry->d_inode;
1771                 /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
1772                 if(*ptmp_inode == NULL) {
1773                         *ptmp_inode = new_inode(file->f_dentry->d_sb);
1774                         if(*ptmp_inode == NULL)
1775                                 return rc;
1776                         rc = 1;
1777                         d_instantiate(tmp_dentry, *ptmp_inode);
1778                 }
1779         } else {
1780                 tmp_dentry = d_alloc(file->f_dentry, qstring);
1781                 if(tmp_dentry == NULL) {
1782                         cERROR(1,("Failed allocating dentry"));
1783                         *ptmp_inode = NULL;
1784                         return rc;
1785                 }
1786                         
1787                 *ptmp_inode = new_inode(file->f_dentry->d_sb);
1788                 tmp_dentry->d_op = &cifs_dentry_ops;
1789                 if(*ptmp_inode == NULL)
1790                         return rc;
1791                 rc = 1;
1792                 d_instantiate(tmp_dentry, *ptmp_inode);
1793                 d_rehash(tmp_dentry);
1794         }
1795
1796         tmp_dentry->d_time = jiffies;
1797         *pnew_dentry = tmp_dentry;
1798         return rc; 
1799 }
1800
1801 static void reset_resume_key(struct file * dir_file, 
1802                                 unsigned char * filename, 
1803                                 unsigned int len,int Unicode,struct nls_table * nls_tab) {
1804         struct cifsFileInfo *cifsFile;
1805
1806         cifsFile = (struct cifsFileInfo *)dir_file->private_data;
1807         if(cifsFile == NULL)
1808                 return;
1809         if(cifsFile->search_resume_name) {
1810                 kfree(cifsFile->search_resume_name);
1811         }
1812
1813         if(Unicode) 
1814                 len *= 2;
1815         cifsFile->resume_name_length = len;
1816
1817         cifsFile->search_resume_name = 
1818                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1819
1820         if(cifsFile->search_resume_name == NULL) {
1821                 cERROR(1,("failed new resume key allocate, length %d",
1822                                   cifsFile->resume_name_length));
1823                 return;
1824         }
1825         if(Unicode)
1826                 cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
1827                         filename, len, nls_tab);
1828         else
1829                 memcpy(cifsFile->search_resume_name, filename, 
1830                    cifsFile->resume_name_length);
1831         cFYI(1,("Reset resume key to: %s with len %d",filename,len));
1832         return;
1833 }
1834
1835
1836
1837 static int
1838 cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
1839              struct file *file, filldir_t filldir, void *direntry)
1840 {
1841         struct inode *tmp_inode;
1842         struct dentry *tmp_dentry;
1843         int object_type,rc;
1844
1845         pqstring->name = pfindData->FileName;
1846         /* pqstring->len is already set by caller */
1847
1848         rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1849         if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
1850                 return -ENOMEM;
1851         }
1852         fill_in_inode(tmp_inode, pfindData, &object_type);
1853         if(rc) {
1854                 /* We have no reliable way to get inode numbers
1855                 from servers w/o Unix extensions yet so we can not set
1856                 i_ino from pfindData yet */
1857
1858                 /* new inode created, let us hash it */
1859                 insert_inode_hash(tmp_inode);
1860         } /* else if inode number changed do we rehash it? */
1861         rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
1862                 tmp_inode->i_ino, object_type);
1863         if(rc) {
1864                 /* due to readdir error we need to recalculate resume 
1865                 key so next readdir will restart on right entry */
1866                 cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
1867         }
1868         dput(tmp_dentry);
1869         return rc;
1870 }
1871
1872 static int
1873 cifs_filldir_unix(struct qstr *pqstring,
1874                   FILE_UNIX_INFO * pUnixFindData, struct file *file,
1875                   filldir_t filldir, void *direntry)
1876 {
1877         struct inode *tmp_inode;
1878         struct dentry *tmp_dentry;
1879         int object_type, rc;
1880
1881         pqstring->name = pUnixFindData->FileName;
1882         pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
1883
1884         rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1885         if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
1886                 return -ENOMEM;
1887         } 
1888         if(rc) {
1889                 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1890
1891                 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
1892                         tmp_inode->i_ino = 
1893                                 (unsigned long)pUnixFindData->UniqueId;
1894                 }
1895                 insert_inode_hash(tmp_inode);
1896         } /* else if i_ino has changed should we rehash it? */
1897         unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
1898         rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
1899                 file->f_pos, tmp_inode->i_ino, object_type);
1900         if(rc) {
1901                 /* due to readdir error we need to recalculate resume 
1902                         key so next readdir will restart on right entry */
1903                 cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
1904         }
1905         dput(tmp_dentry);
1906         return rc;
1907 }
1908
1909 int
1910 cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
1911 {
1912         int rc = 0;
1913         int xid;
1914         int Unicode = FALSE;
1915         int UnixSearch = FALSE;
1916         unsigned int bufsize, i;
1917         __u16 searchHandle;
1918         struct cifs_sb_info *cifs_sb;
1919         struct cifsTconInfo *pTcon;
1920         struct cifsFileInfo *cifsFile = NULL;
1921         char *full_path = NULL;
1922         char *data;
1923         struct qstr qstring;
1924         T2_FFIRST_RSP_PARMS findParms;
1925         T2_FNEXT_RSP_PARMS findNextParms;
1926         FILE_DIRECTORY_INFO *pfindData;
1927         FILE_DIRECTORY_INFO *lastFindData;
1928         FILE_UNIX_INFO *pfindDataUnix;
1929
1930
1931     /* BB removeme begin */
1932         if(!experimEnabled)
1933                 return cifs_readdir2(file,direntry,filldir);
1934     /* BB removeme end */
1935
1936
1937         xid = GetXid();
1938
1939         if(file->f_dentry == NULL) {
1940                 rc = -EIO;
1941                 FreeXid(xid);
1942                 return rc;
1943         }
1944         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1945         pTcon = cifs_sb->tcon;
1946         bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
1947         if(bufsize > CIFSMaxBufSize) {
1948                 rc = -EIO;
1949                 FreeXid(xid);
1950                 return rc;
1951         }
1952         data = kmalloc(bufsize, GFP_KERNEL);
1953         pfindData = (FILE_DIRECTORY_INFO *) data;
1954         if(data == NULL) {
1955                 rc = -ENOMEM;
1956                 FreeXid(xid);
1957                 return rc;
1958         }
1959         down(&file->f_dentry->d_sb->s_vfs_rename_sem);
1960         full_path = build_wildcard_path_from_dentry(file->f_dentry);
1961         up(&file->f_dentry->d_sb->s_vfs_rename_sem);
1962
1963         if(full_path == NULL) {
1964                 kfree(data);
1965                 FreeXid(xid);
1966                 return -ENOMEM;
1967         }
1968         cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
1969
1970         switch ((int) file->f_pos) {
1971         case 0:
1972                 if (filldir(direntry, ".", 1, file->f_pos,
1973                      file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
1974                         cERROR(1, ("Filldir for current dir failed "));
1975                         break;
1976                 }
1977                 file->f_pos++;
1978                 /* fallthrough */
1979         case 1:
1980                 if (filldir(direntry, "..", 2, file->f_pos,
1981                      file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1982                         cERROR(1, ("Filldir for parent dir failed "));
1983                         break;
1984                 }
1985                 file->f_pos++;
1986                 /* fallthrough */
1987         case 2:
1988                 if (file->private_data != NULL) {
1989                         cifsFile =
1990                                 (struct cifsFileInfo *) file->private_data;
1991                         if (cifsFile->srch_inf.endOfSearch) {
1992                                 if(cifsFile->srch_inf.emptyDir) {
1993                                         cFYI(1, ("End of search, empty dir"));
1994                                         rc = 0;
1995                                         break;
1996                                 }
1997                         } else {
1998                                 cifsFile->invalidHandle = TRUE;
1999                                 CIFSFindClose(xid, pTcon, cifsFile->netfid);
2000                         }
2001                         if(cifsFile->search_resume_name) {
2002                                 kfree(cifsFile->search_resume_name);
2003                                 cifsFile->search_resume_name = NULL;
2004                         }
2005                 }
2006                 rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
2007                                 &findParms, cifs_sb->local_nls,
2008                                 &Unicode, &UnixSearch);
2009                 cFYI(1, ("Count: %d  End: %d ",
2010                         le16_to_cpu(findParms.SearchCount),
2011                         le16_to_cpu(findParms.EndofSearch)));
2012  
2013                 if (rc == 0) {
2014                         __u16 count = le16_to_cpu(findParms.SearchCount);
2015                         searchHandle = findParms.SearchHandle;
2016                         if(file->private_data == NULL)
2017                                 file->private_data =
2018                                         kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
2019                         if (file->private_data) {
2020                                 memset(file->private_data, 0,
2021                                        sizeof (struct cifsFileInfo));
2022                                 cifsFile =
2023                                     (struct cifsFileInfo *) file->private_data;
2024                                 cifsFile->netfid = searchHandle;
2025                                 cifsFile->invalidHandle = FALSE;
2026                                 init_MUTEX(&cifsFile->fh_sem);
2027                         } else {
2028                                 rc = -ENOMEM;
2029                                 break;
2030                         }
2031
2032                         renew_parental_timestamps(file->f_dentry);
2033                         lastFindData = 
2034                                 (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
2035                                         le16_to_cpu(findParms.LastNameOffset));
2036                         if((char *)lastFindData > (char *)pfindData + bufsize) {
2037                                 cFYI(1,("last search entry past end of packet"));
2038                                 rc = -EIO;
2039                                 break;
2040                         }
2041                         /* Offset of resume key same for levels 257 and 514 */
2042                         cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
2043                         if(UnixSearch == FALSE) {
2044                                 cifsFile->resume_name_length = 
2045                                         le32_to_cpu(lastFindData->FileNameLength);
2046                                 if(cifsFile->resume_name_length > bufsize - 64) {
2047                                         cFYI(1,("Illegal resume file name length %d",
2048                                                 cifsFile->resume_name_length));
2049                                         rc = -ENOMEM;
2050                                         break;
2051                                 }
2052                                 cifsFile->search_resume_name = 
2053                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
2054                                 cFYI(1,("Last file: %s with name %d bytes long",
2055                                         lastFindData->FileName,
2056                                         cifsFile->resume_name_length));
2057                                 if(cifsFile->search_resume_name == NULL) {
2058                                         rc = -ENOMEM;
2059                                         break;
2060                                 }
2061                                 memcpy(cifsFile->search_resume_name,
2062                                         lastFindData->FileName, 
2063                                         cifsFile->resume_name_length);
2064                         } else {
2065                                 pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
2066                                 if (Unicode == TRUE) {
2067                                         for(i=0;(pfindDataUnix->FileName[i] 
2068                                                     | pfindDataUnix->FileName[i+1]);
2069                                                 i+=2) {
2070                                                 if(i > bufsize-64)
2071                                                         break;
2072                                         }
2073                                         cifsFile->resume_name_length = i + 2;
2074                                 } else {
2075                                         cifsFile->resume_name_length = 
2076                                                 strnlen(pfindDataUnix->FileName,
2077                                                         bufsize-63);
2078                                 }
2079                                 if(cifsFile->resume_name_length > bufsize - 64) {
2080                                         cFYI(1,("Illegal resume file name length %d",
2081                                                 cifsFile->resume_name_length));
2082                                         rc = -ENOMEM;
2083                                         break;
2084                                 }
2085                                 cifsFile->search_resume_name = 
2086                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
2087                                 cFYI(1,("Last file: %s with name %d bytes long",
2088                                         pfindDataUnix->FileName,
2089                                         cifsFile->resume_name_length));
2090                                 if(cifsFile->search_resume_name == NULL) {
2091                                         rc = -ENOMEM;
2092                                         break;
2093                                 }
2094                                 memcpy(cifsFile->search_resume_name,
2095                                         pfindDataUnix->FileName, 
2096                                         cifsFile->resume_name_length);
2097                         }
2098                         for (i = 2; i < count + 2; i++) {
2099                                 if (UnixSearch == FALSE) {
2100                                         __u32 len = le32_to_cpu(pfindData->FileNameLength);
2101                                         if (Unicode == TRUE)
2102                                                 len =
2103                                                     cifs_strfromUCS_le
2104                                                     (pfindData->FileName,
2105                                                      (wchar_t *)
2106                                                      pfindData->FileName,
2107                                                      len / 2,
2108                                                      cifs_sb->local_nls);
2109                                         qstring.len = len;
2110                                         if (((len != 1)
2111                                              || (pfindData->FileName[0] != '.'))
2112                                             && ((len != 2)
2113                                                 || (pfindData->
2114                                                     FileName[0] != '.')
2115                                                 || (pfindData->
2116                                                     FileName[1] != '.'))) {
2117                                                 if(cifs_filldir(&qstring,
2118                                                              pfindData,
2119                                                              file, filldir,
2120                                                              direntry)) {
2121                                                         /* do not end search if
2122                                                                 kernel not ready to take
2123                                                                 remaining entries yet */
2124                                                         reset_resume_key(file, pfindData->FileName,qstring.len,
2125                                                                 Unicode, cifs_sb->local_nls);
2126                                                         findParms.EndofSearch = 0;
2127                                                         break;
2128                                                 }
2129                                                 file->f_pos++;
2130                                         }
2131                                 } else {        /* UnixSearch */
2132                                         pfindDataUnix =
2133                                             (FILE_UNIX_INFO *) pfindData;
2134                                         if (Unicode == TRUE)
2135                                                 qstring.len =
2136                                                         cifs_strfromUCS_le
2137                                                         (pfindDataUnix->FileName,
2138                                                         (wchar_t *)
2139                                                         pfindDataUnix->FileName,
2140                                                         MAX_PATHCONF,
2141                                                         cifs_sb->local_nls);
2142                                         else
2143                                                 qstring.len =
2144                                                         strnlen(pfindDataUnix->
2145                                                           FileName,
2146                                                           MAX_PATHCONF);
2147                                         if (((qstring.len != 1)
2148                                              || (pfindDataUnix->
2149                                                  FileName[0] != '.'))
2150                                             && ((qstring.len != 2)
2151                                                 || (pfindDataUnix->
2152                                                     FileName[0] != '.')
2153                                                 || (pfindDataUnix->
2154                                                     FileName[1] != '.'))) {
2155                                                 if(cifs_filldir_unix(&qstring,
2156                                                                   pfindDataUnix,
2157                                                                   file,
2158                                                                   filldir,
2159                                                                   direntry)) {
2160                                                         /* do not end search if
2161                                                                 kernel not ready to take
2162                                                                 remaining entries yet */
2163                                                         findParms.EndofSearch = 0;
2164                                                         reset_resume_key(file, pfindDataUnix->FileName,
2165                                                                 qstring.len,Unicode,cifs_sb->local_nls);
2166                                                         break;
2167                                                 }
2168                                                 file->f_pos++;
2169                                         }
2170                                 }
2171                                 /* works also for Unix ff struct since first field of both */
2172                                 pfindData = 
2173                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData
2174                                                  + le32_to_cpu(pfindData->NextEntryOffset));
2175                                 /* BB also should check to make sure that pointer is not beyond the end of the SMB */
2176                                 /* if(pfindData > lastFindData) rc = -EIO; break; */
2177                         }       /* end for loop */
2178                         if ((findParms.EndofSearch != 0) && cifsFile) {
2179                                 cifsFile->srch_inf.endOfSearch = TRUE;
2180                                 if(findParms.SearchCount == cpu_to_le16(2))
2181                                         cifsFile->srch_inf.emptyDir = TRUE;
2182                         }
2183                 } else {
2184                         if (cifsFile)
2185                                 cifsFile->srch_inf.endOfSearch = TRUE;
2186                         /* unless parent directory gone do not return error */
2187                         rc = 0;
2188                 }
2189                 break;
2190         default:
2191                 if (file->private_data == NULL) {
2192                         rc = -EBADF;
2193                         cFYI(1,
2194                              ("Readdir on closed srch, pos = %lld",
2195                               file->f_pos));
2196                 } else {
2197                         cifsFile = (struct cifsFileInfo *) file->private_data;
2198                         if (cifsFile->srch_inf.endOfSearch) {
2199                                 rc = 0;
2200                                 cFYI(1, ("End of search "));
2201                                 break;
2202                         }
2203                         searchHandle = cifsFile->netfid;
2204                         rc = CIFSFindNext(xid, pTcon, pfindData,
2205                                 &findNextParms, searchHandle, 
2206                                 cifsFile->search_resume_name,
2207                                 cifsFile->resume_name_length,
2208                                 cifsFile->srch_inf.resume_key,
2209                                 &Unicode, &UnixSearch);
2210                         cFYI(1,("Count: %d  End: %d ",
2211                               le16_to_cpu(findNextParms.SearchCount),
2212                               le16_to_cpu(findNextParms.EndofSearch)));
2213                         if ((rc == 0) && (findNextParms.SearchCount != 0)) {
2214                         /* BB save off resume key, key name and name length  */
2215                                 __u16 count = le16_to_cpu(findNextParms.SearchCount);
2216                                 lastFindData = 
2217                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData 
2218                                         + le16_to_cpu(findNextParms.LastNameOffset));
2219                                 if((char *)lastFindData > (char *)pfindData + bufsize) {
2220                                         cFYI(1,("last search entry past end of packet"));
2221                                         rc = -EIO;
2222                                         break;
2223                                 }
2224                                 /* Offset of resume key same for levels 257 and 514 */
2225                                 cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
2226
2227                                 if(UnixSearch == FALSE) {
2228                                         cifsFile->resume_name_length = 
2229                                                 le32_to_cpu(lastFindData->FileNameLength);
2230                                         if(cifsFile->resume_name_length > bufsize - 64) {
2231                                                 cFYI(1,("Illegal resume file name length %d",
2232                                                         cifsFile->resume_name_length));
2233                                                 rc = -ENOMEM;
2234                                                 break;
2235                                         }
2236                                         /* Free the memory allocated by previous findfirst 
2237                                         or findnext call - we can not reuse the memory since
2238                                         the resume name may not be same string length */
2239                                         if(cifsFile->search_resume_name)
2240                                                 kfree(cifsFile->search_resume_name);
2241                                         cifsFile->search_resume_name = 
2242                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
2243                                         cFYI(1,("Last file: %s with name %d bytes long",
2244                                                 lastFindData->FileName,
2245                                                 cifsFile->resume_name_length));
2246                                         if(cifsFile->search_resume_name == NULL) {
2247                                                 rc = -ENOMEM;
2248                                                 break;
2249                                         }
2250                                         
2251                                         memcpy(cifsFile->search_resume_name,
2252                                                 lastFindData->FileName, 
2253                                                 cifsFile->resume_name_length);
2254                                 } else {
2255                                         pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
2256                                         if (Unicode == TRUE) {
2257                                                 for(i=0;(pfindDataUnix->FileName[i] 
2258                                                                 | pfindDataUnix->FileName[i+1]);
2259                                                         i+=2) {
2260                                                         if(i > bufsize-64)
2261                                                                 break;
2262                                                 }
2263                                                 cifsFile->resume_name_length = i + 2;
2264                                         } else {
2265                                                 cifsFile->resume_name_length = 
2266                                                         strnlen(pfindDataUnix->
2267                                                          FileName,
2268                                                          MAX_PATHCONF);
2269                                         }
2270                                         if(cifsFile->resume_name_length > bufsize - 64) {
2271                                                 cFYI(1,("Illegal resume file name length %d",
2272                                                                 cifsFile->resume_name_length));
2273                                                 rc = -ENOMEM;
2274                                                 break;
2275                                         }
2276                                         /* Free the memory allocated by previous findfirst 
2277                                         or findnext call - we can not reuse the memory since
2278                                         the resume name may not be same string length */
2279                                         if(cifsFile->search_resume_name)
2280                                                 kfree(cifsFile->search_resume_name);
2281                                         cifsFile->search_resume_name = 
2282                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
2283                                         cFYI(1,("fnext last file: %s with name %d bytes long",
2284                                                 pfindDataUnix->FileName,
2285                                                 cifsFile->resume_name_length));
2286                                         if(cifsFile->search_resume_name == NULL) {
2287                                                 rc = -ENOMEM;
2288                                                 break;
2289                                         }
2290                                         memcpy(cifsFile->search_resume_name,
2291                                                 pfindDataUnix->FileName, 
2292                                                 cifsFile->resume_name_length);
2293                                 }
2294
2295                                 for (i = 0; i < count; i++) {
2296                                         __u32 len = le32_to_cpu(pfindData->
2297                                                         FileNameLength);
2298                                         if (UnixSearch == FALSE) {
2299                                                 if (Unicode == TRUE)
2300                                                         len =
2301                                                           cifs_strfromUCS_le
2302                                                           (pfindData->FileName,
2303                                                           (wchar_t *)
2304                                                           pfindData->FileName,
2305                                                           len / 2,
2306                                                           cifs_sb->local_nls);
2307                                                 qstring.len = len;
2308                                                 if (((len != 1)
2309                                                     || (pfindData->FileName[0] != '.'))
2310                                                     && ((len != 2)
2311                                                         || (pfindData->FileName[0] != '.')
2312                                                         || (pfindData->FileName[1] !=
2313                                                             '.'))) {
2314                                                         if(cifs_filldir
2315                                                             (&qstring,
2316                                                              pfindData,
2317                                                              file, filldir,
2318                                                              direntry)) {
2319                                                         /* do not end search if
2320                                                                 kernel not ready to take
2321                                                                 remaining entries yet */
2322                                                                 findNextParms.EndofSearch = 0;
2323                                                                 reset_resume_key(file, pfindData->FileName,qstring.len,
2324                                                                         Unicode,cifs_sb->local_nls);
2325                                                                 break;
2326                                                         }
2327                                                         file->f_pos++;
2328                                                 }
2329                                         } else {        /* UnixSearch */
2330                                                 pfindDataUnix =
2331                                                     (FILE_UNIX_INFO *)
2332                                                     pfindData;
2333                                                 if (Unicode == TRUE)
2334                                                         qstring.len =
2335                                                           cifs_strfromUCS_le
2336                                                           (pfindDataUnix->FileName,
2337                                                           (wchar_t *)
2338                                                           pfindDataUnix->FileName,
2339                                                           MAX_PATHCONF,
2340                                                           cifs_sb->local_nls);
2341                                                 else
2342                                                         qstring.len =
2343                                                           strnlen
2344                                                           (pfindDataUnix->
2345                                                           FileName,
2346                                                           MAX_PATHCONF);
2347                                                 if (((qstring.len != 1)
2348                                                      || (pfindDataUnix->
2349                                                          FileName[0] != '.'))
2350                                                     && ((qstring.len != 2)
2351                                                         || (pfindDataUnix->
2352                                                             FileName[0] != '.')
2353                                                         || (pfindDataUnix->
2354                                                             FileName[1] !=
2355                                                             '.'))) {
2356                                                         if(cifs_filldir_unix
2357                                                             (&qstring,
2358                                                              pfindDataUnix,
2359                                                              file, filldir,
2360                                                              direntry)) {
2361                                                                 /* do not end search if
2362                                                                 kernel not ready to take
2363                                                                 remaining entries yet */
2364                                                                 findNextParms.EndofSearch = 0;
2365                                                                 reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
2366                                                                         Unicode,cifs_sb->local_nls);
2367                                                                 break;
2368                                                         }
2369                                                         file->f_pos++;
2370                                                 }
2371                                         }
2372                                         pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
2373                                                 le32_to_cpu(pfindData->NextEntryOffset));
2374         /* works also for Unix find struct since first field of both */
2375         /* BB also should check to ensure pointer not beyond end of SMB */
2376                                 } /* end for loop */
2377                                 if (findNextParms.EndofSearch != 0) {
2378                                         cifsFile->srch_inf.endOfSearch = TRUE;
2379                                 }
2380                         } else {
2381                                 cifsFile->srch_inf.endOfSearch = TRUE;
2382                                 rc = 0; /* unless parent directory disappeared - do not
2383                                 return error here (eg Access Denied or no more files) */
2384                         }
2385                 }
2386         } /* end switch */
2387         if (data)
2388                 kfree(data);
2389         if (full_path)
2390                 kfree(full_path);
2391         FreeXid(xid);
2392
2393         return rc;
2394 }
2395 int cifs_prepare_write(struct file *file, struct page *page,
2396                         unsigned from, unsigned to)
2397 {
2398         int rc = 0;
2399         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2400         cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
2401         if (!PageUptodate(page)) {
2402         /*      if (to - from != PAGE_CACHE_SIZE) {
2403                         void *kaddr = kmap_atomic(page, KM_USER0);
2404                         memset(kaddr, 0, from);
2405                         memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
2406                         flush_dcache_page(page);
2407                         kunmap_atomic(kaddr, KM_USER0);
2408                 } */
2409                 /* If we are writing a full page it will be up to date,
2410                 no need to read from the server */
2411                 if((to==PAGE_CACHE_SIZE) && (from == 0))
2412                         SetPageUptodate(page);
2413
2414                 /* might as well read a page, it is fast enough */
2415                 if((file->f_flags & O_ACCMODE) != O_WRONLY) {
2416                         rc = cifs_readpage_worker(file,page,&offset);
2417                 } else {
2418                 /* should we try using another
2419                 file handle if there is one - how would we lock it
2420                 to prevent close of that handle racing with this read? */
2421                 /* In any case this will be written out by commit_write */
2422                 }
2423         }
2424
2425         /* BB should we pass any errors back? e.g. if we do not have read access to the file */
2426         return 0;
2427 }
2428
2429
2430 struct address_space_operations cifs_addr_ops = {
2431         .readpage = cifs_readpage,
2432         .readpages = cifs_readpages,
2433         .writepage = cifs_writepage,
2434         .prepare_write = cifs_prepare_write, 
2435         .commit_write = cifs_commit_write,
2436         .set_page_dirty = __set_page_dirty_nobuffers,
2437    /* .sync_page = cifs_sync_page, */
2438         /*.direct_IO = */
2439 };