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