VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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,xid);
219                                 else
220                                         rc = cifs_get_inode_info(&file->f_dentry->d_inode,
221                                                 full_path, buf, inode->i_sb,xid);
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,xid);
371                                 else
372                                         rc = cifs_get_inode_info(&inode,
373                                                 full_path, NULL, inode->i_sb,xid);
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         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
592         if(cifs_sb == NULL) {
593                 return -EBADF;
594         }
595         pTcon = cifs_sb->tcon;
596
597         /*cFYI(1,
598            (" write %d bytes to offset %lld of %s", write_size,
599            *poffset, file->f_dentry->d_name.name)); */
600
601         if (file->private_data == NULL) {
602                 return -EBADF;
603         } else {
604                 open_file = (struct cifsFileInfo *) file->private_data;
605         }
606         
607         xid = GetXid();
608         if(file->f_dentry->d_inode == NULL) {
609                 FreeXid(xid);
610                 return -EBADF;
611         }
612
613         if (*poffset > file->f_dentry->d_inode->i_size)
614                 long_op = 2;  /* writes past end of file can take a long time */
615         else
616                 long_op = 1;
617
618         for (total_written = 0; write_size > total_written;
619              total_written += bytes_written) {
620                 rc = -EAGAIN;
621                 while(rc == -EAGAIN) {
622                         if(file->private_data == NULL) {
623                                 /* file has been closed on us */
624                                 FreeXid(xid);
625                         /* if we have gotten here we have written some data
626                         and blocked, and the file has been freed on us
627                         while we blocked so return what we managed to write */
628                                 return total_written;
629                         } 
630                         if(open_file->closePend) {
631                                 FreeXid(xid);
632                                 if(total_written)
633                                         return total_written;
634                                 else
635                                         return -EBADF;
636                         }
637                         if (open_file->invalidHandle) {
638                                 if((file->f_dentry == NULL) ||
639                                    (file->f_dentry->d_inode == NULL)) {
640                                         FreeXid(xid);
641                                         return total_written;
642                                 }
643                                 /* we could deadlock if we called
644                                  filemap_fdatawait from here so tell
645                                 reopen_file not to flush data to server now */
646                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
647                                         file,FALSE);
648                                 if(rc != 0)
649                                         break;
650                         }
651
652                         rc = CIFSSMBWrite(xid, pTcon,
653                                    open_file->netfid,
654                                   write_size - total_written, *poffset,
655                                   &bytes_written,
656                                   write_data + total_written, long_op);
657                 }
658                 if (rc || (bytes_written == 0)) {
659                         if (total_written)
660                                 break;
661                         else {
662                                 FreeXid(xid);
663                                 return rc;
664                         }
665                 } else
666                         *poffset += bytes_written;
667                 long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
668         }
669
670 #ifdef CONFIG_CIFS_STATS
671         if(total_written > 0) {
672                 atomic_inc(&pTcon->num_writes);
673                 spin_lock(&pTcon->stat_lock);
674                 pTcon->bytes_written += total_written;
675                 spin_unlock(&pTcon->stat_lock);
676         }
677 #endif          
678
679         /* since the write may have blocked check these pointers again */
680         if(file->f_dentry) {
681                 if(file->f_dentry->d_inode) {
682                         file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
683                                 CURRENT_TIME;
684                         if (total_written > 0) {
685                                 if (*poffset > file->f_dentry->d_inode->i_size)
686                                         i_size_write(file->f_dentry->d_inode, *poffset);
687                         }
688                         mark_inode_dirty_sync(file->f_dentry->d_inode);
689                 }
690         }
691         FreeXid(xid);
692         return total_written;
693 }
694
695 static int
696 cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
697 {
698         struct address_space *mapping = page->mapping;
699         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
700         char * write_data;
701         int rc = -EFAULT;
702         int bytes_written = 0;
703         struct cifs_sb_info *cifs_sb;
704         struct cifsTconInfo *pTcon;
705         struct inode *inode;
706         struct cifsInodeInfo *cifsInode;
707         struct cifsFileInfo *open_file = NULL;
708         struct list_head *tmp;
709         struct list_head *tmp1;
710
711         if (!mapping) {
712                 return -EFAULT;
713         } else if(!mapping->host) {
714                 return -EFAULT;
715         }
716
717         inode = page->mapping->host;
718         cifs_sb = CIFS_SB(inode->i_sb);
719         pTcon = cifs_sb->tcon;
720
721         offset += (loff_t)from;
722         write_data = kmap(page);
723         write_data += from;
724
725         if((to > PAGE_CACHE_SIZE) || (from > to)) {
726                 kunmap(page);
727                 return -EIO;
728         }
729
730         /* racing with truncate? */
731         if(offset > mapping->host->i_size) {
732                 kunmap(page);
733                 return 0; /* don't care */
734         }
735
736         /* check to make sure that we are not extending the file */
737         if(mapping->host->i_size - offset < (loff_t)to)
738                 to = (unsigned)(mapping->host->i_size - offset); 
739                 
740
741         cifsInode = CIFS_I(mapping->host);
742         read_lock(&GlobalSMBSeslock); 
743         /* BB we should start at the end */
744         list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
745                 open_file = list_entry(tmp,struct cifsFileInfo, flist);
746                 if(open_file->closePend)
747                         continue;
748                 /* We check if file is open for writing first */
749                 if((open_file->pfile) && 
750                    ((open_file->pfile->f_flags & O_RDWR) || 
751                         (open_file->pfile->f_flags & O_WRONLY))) {
752                         read_unlock(&GlobalSMBSeslock);
753                         bytes_written = cifs_write(open_file->pfile, write_data,
754                                         to-from, &offset);
755                         read_lock(&GlobalSMBSeslock);
756                 /* Does mm or vfs already set times? */
757                         inode->i_atime = inode->i_mtime = CURRENT_TIME;
758                         if ((bytes_written > 0) && (offset)) {
759                                 rc = 0;
760                         } else if(bytes_written < 0) {
761                                 if(rc == -EBADF) {
762                                 /* have seen a case in which
763                                 kernel seemed to have closed/freed a file
764                                 even with writes active so we might as well
765                                 see if there are other file structs to try
766                                 for the same inode before giving up */
767                                         continue;
768                                 } else
769                                         rc = bytes_written;
770                         }
771                         break;  /* now that we found a valid file handle
772                                 and tried to write to it we are done, no
773                                 sense continuing to loop looking for another */
774                 }
775                 if(tmp->next == NULL) {
776                         cFYI(1,("File instance %p removed",tmp));
777                         break;
778                 }
779         }
780         read_unlock(&GlobalSMBSeslock);
781         if(open_file == NULL) {
782                 cFYI(1,("No writeable filehandles for inode"));
783                 rc = -EIO;
784         }
785
786         kunmap(page);
787         return rc;
788 }
789
790 #if 0
791 static int
792 cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
793 {
794         int rc = -EFAULT;
795         int xid;
796
797         xid = GetXid();
798 /* call 16K write then Setpageuptodate */
799         FreeXid(xid);
800         return rc;
801 }
802 #endif
803
804 static int
805 cifs_writepage(struct page* page, struct writeback_control *wbc)
806 {
807         int rc = -EFAULT;
808         int xid;
809
810         xid = GetXid();
811 /* BB add check for wbc flags */
812         page_cache_get(page);
813         if (!PageUptodate(page)) {
814                 cFYI(1,("ppw - page not up to date"));
815         }
816         
817         rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
818         SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
819         unlock_page(page);
820         page_cache_release(page);       
821         FreeXid(xid);
822         return rc;
823 }
824
825 static int
826 cifs_commit_write(struct file *file, struct page *page, unsigned offset,
827                   unsigned to)
828 {
829         int xid;
830         int rc = 0;
831         struct inode *inode = page->mapping->host;
832         loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
833         char * page_data;
834
835         xid = GetXid();
836         cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
837         if (position > inode->i_size){
838                 i_size_write(inode, position);
839                 /*if (file->private_data == NULL) {
840                         rc = -EBADF;
841                 } else {
842                         open_file = (struct cifsFileInfo *)file->private_data;
843                         cifs_sb = CIFS_SB(inode->i_sb);
844                         rc = -EAGAIN;
845                         while(rc == -EAGAIN) {
846                                 if((open_file->invalidHandle) && 
847                                   (!open_file->closePend)) {
848                                         rc = cifs_reopen_file(file->f_dentry->d_inode,file);
849                                         if(rc != 0)
850                                                 break;
851                                 }
852                                 if(!open_file->closePend) {
853                                         rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, 
854                                                 position, open_file->netfid,
855                                                 open_file->pid,FALSE);
856                                 } else {
857                                         rc = -EBADF;
858                                         break;
859                                 }
860                         }
861                         cFYI(1,(" SetEOF (commit write) rc = %d",rc));
862                 }*/
863         }
864         if (!PageUptodate(page)) {
865                 position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
866                 /* can not rely on (or let) writepage write this data */
867                 if(to < offset) {
868                         cFYI(1,("Illegal offsets, can not copy from %d to %d",
869                                 offset,to));
870                         FreeXid(xid);
871                         return rc;
872                 }
873                 /* this is probably better than directly calling 
874                 partialpage_write since in this function
875                 the file handle is known which we might as well
876                 leverage */
877                 /* BB check if anything else missing out of ppw */
878                 /* such as updating last write time */
879                 page_data = kmap(page);
880                 rc = cifs_write(file, page_data+offset,to-offset,
881                                         &position);
882                 if(rc > 0)
883                         rc = 0;
884                 /* else if rc < 0 should we set writebehind rc? */
885                 kunmap(page);
886         } else {        
887                 set_page_dirty(page);
888         }
889
890         FreeXid(xid);
891         return rc;
892 }
893
894 int
895 cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
896 {
897         int xid;
898         int rc = 0;
899         struct inode * inode = file->f_dentry->d_inode;
900
901         xid = GetXid();
902
903         cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
904                 dentry->d_name.name, datasync));
905         
906         rc = filemap_fdatawrite(inode->i_mapping);
907         if(rc == 0)
908                 CIFS_I(inode)->write_behind_rc = 0;
909         FreeXid(xid);
910         return rc;
911 }
912
913 /* static int
914 cifs_sync_page(struct page *page)
915 {
916         struct address_space *mapping;
917         struct inode *inode;
918         unsigned long index = page->index;
919         unsigned int rpages = 0;
920         int rc = 0;
921
922         cFYI(1,("sync page %p",page));
923         mapping = page->mapping;
924         if (!mapping)
925                 return 0;
926         inode = mapping->host;
927         if (!inode)
928                 return 0;*/
929
930 /*      fill in rpages then 
931     result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
932
933 /*   cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
934
935         if (rc < 0)
936                 return rc;
937         return 0;
938 } */
939
940 /*
941  * As file closes, flush all cached write data for this inode checking
942  * for write behind errors.
943  *
944  */
945 int cifs_flush(struct file *file)
946 {
947         struct inode * inode = file->f_dentry->d_inode;
948         int rc = 0;
949
950         /* Rather than do the steps manually: */
951         /* lock the inode for writing */
952         /* loop through pages looking for write behind data (dirty pages) */
953         /* coalesce into contiguous 16K (or smaller) chunks to write to server */
954         /* send to server (prefer in parallel) */
955         /* deal with writebehind errors */
956         /* unlock inode for writing */
957         /* filemapfdatawrite appears easier for the time being */
958
959         rc = filemap_fdatawrite(inode->i_mapping);
960         if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
961                 CIFS_I(inode)->write_behind_rc = 0;
962                 
963         cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
964
965         return rc;
966 }
967
968
969 ssize_t
970 cifs_read(struct file * file, char *read_data, size_t read_size,
971           loff_t * poffset)
972 {
973         int rc = -EACCES;
974         unsigned int bytes_read = 0;
975         unsigned int total_read;
976         unsigned int current_read_size;
977         struct cifs_sb_info *cifs_sb;
978         struct cifsTconInfo *pTcon;
979         int xid;
980         char * current_offset;
981         struct cifsFileInfo * open_file;
982
983         xid = GetXid();
984         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
985         pTcon = cifs_sb->tcon;
986
987         if (file->private_data == NULL) {
988                 FreeXid(xid);
989                 return -EBADF;
990         }
991         open_file = (struct cifsFileInfo *)file->private_data;
992
993         if((file->f_flags & O_ACCMODE) == O_WRONLY) {
994                 cFYI(1,("attempting read on write only file instance"));
995         }
996
997         for (total_read = 0,current_offset=read_data; read_size > total_read;
998                                 total_read += bytes_read,current_offset+=bytes_read) {
999                 current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
1000                 rc = -EAGAIN;
1001                 while(rc == -EAGAIN) {
1002                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1003                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
1004                                         file,TRUE);
1005                                 if(rc != 0)
1006                                         break;
1007                         }
1008
1009                         rc = CIFSSMBRead(xid, pTcon,
1010                                  open_file->netfid,
1011                                  current_read_size, *poffset,
1012                                  &bytes_read, &current_offset);
1013                 }
1014                 if (rc || (bytes_read == 0)) {
1015                         if (total_read) {
1016                                 break;
1017                         } else {
1018                                 FreeXid(xid);
1019                                 return rc;
1020                         }
1021                 } else {
1022 #ifdef CONFIG_CIFS_STATS
1023                         atomic_inc(&pTcon->num_reads);
1024                         spin_lock(&pTcon->stat_lock);
1025                         pTcon->bytes_read += total_read;
1026                         spin_unlock(&pTcon->stat_lock);
1027 #endif
1028                         *poffset += bytes_read;
1029                 }
1030         }
1031         FreeXid(xid);
1032         return total_read;
1033 }
1034
1035 int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
1036 {
1037         struct dentry * dentry = file->f_dentry;
1038         int     rc, xid;
1039
1040         xid = GetXid();
1041         rc = cifs_revalidate(dentry);
1042         if (rc) {
1043                 cFYI(1,("Validation prior to mmap failed, error=%d", rc));
1044                 FreeXid(xid);
1045                 return rc;
1046         }
1047         rc = generic_file_mmap(file, vma);
1048         FreeXid(xid);
1049         return rc;
1050 }
1051
1052 static void cifs_copy_cache_pages(struct address_space *mapping, 
1053                 struct list_head *pages, int bytes_read, 
1054                 char *data,struct pagevec * plru_pvec)
1055 {
1056         struct page *page;
1057         char * target;
1058
1059         while (bytes_read > 0) {
1060                 if(list_empty(pages))
1061                         break;
1062
1063                 page = list_entry(pages->prev, struct page, lru);
1064                 list_del(&page->lru);
1065
1066                 if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
1067                         page_cache_release(page);
1068                         cFYI(1,("Add page cache failed"));
1069                         continue;
1070                 }
1071
1072                 target = kmap_atomic(page,KM_USER0);
1073
1074                 if(PAGE_CACHE_SIZE > bytes_read) {
1075                         memcpy(target,data,bytes_read);
1076                         /* zero the tail end of this partial page */
1077                         memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
1078                         bytes_read = 0;
1079                 } else {
1080                         memcpy(target,data,PAGE_CACHE_SIZE);
1081                         bytes_read -= PAGE_CACHE_SIZE;
1082                 }
1083                 kunmap_atomic(target,KM_USER0);
1084
1085                 flush_dcache_page(page);
1086                 SetPageUptodate(page);
1087                 unlock_page(page);
1088                 if (!pagevec_add(plru_pvec, page))
1089                         __pagevec_lru_add(plru_pvec);
1090                 data += PAGE_CACHE_SIZE;
1091         }
1092         return;
1093 }
1094
1095
1096 static int
1097 cifs_readpages(struct file *file, struct address_space *mapping,
1098                 struct list_head *page_list, unsigned num_pages)
1099 {
1100         int rc = -EACCES;
1101         int xid;
1102         loff_t offset;
1103         struct page * page;
1104         struct cifs_sb_info *cifs_sb;
1105         struct cifsTconInfo *pTcon;
1106         int bytes_read = 0;
1107         unsigned int read_size,i;
1108         char * smb_read_data = NULL;
1109         struct smb_com_read_rsp * pSMBr;
1110         struct pagevec lru_pvec;
1111         struct cifsFileInfo * open_file;
1112
1113         xid = GetXid();
1114         if (file->private_data == NULL) {
1115                 FreeXid(xid);
1116                 return -EBADF;
1117         }
1118         open_file = (struct cifsFileInfo *)file->private_data;
1119         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1120         pTcon = cifs_sb->tcon;
1121
1122         pagevec_init(&lru_pvec, 0);
1123
1124         for(i = 0;i<num_pages;) {
1125                 unsigned contig_pages;
1126                 struct page * tmp_page;
1127                 unsigned long expected_index;
1128
1129                 if(list_empty(page_list)) {
1130                         break;
1131                 }
1132                 page = list_entry(page_list->prev, struct page, lru);
1133                 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1134
1135                 /* count adjacent pages that we will read into */
1136                 contig_pages = 0;
1137                 expected_index = list_entry(page_list->prev,struct page,lru)->index;
1138                 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1139                         if(tmp_page->index == expected_index) {
1140                                 contig_pages++;
1141                                 expected_index++;
1142                         } else {
1143                                 break; 
1144                         }
1145                 }
1146                 if(contig_pages + i >  num_pages) {
1147                         contig_pages = num_pages - i;
1148                 }
1149
1150                 /* for reads over a certain size could initiate async read ahead */
1151
1152                 read_size = contig_pages * PAGE_CACHE_SIZE;
1153                 /* Read size needs to be in multiples of one page */
1154                 read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
1155
1156                 rc = -EAGAIN;
1157                 while(rc == -EAGAIN) {
1158                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1159                                 rc = cifs_reopen_file(file->f_dentry->d_inode,
1160                                         file, TRUE);
1161                                 if(rc != 0)
1162                                         break;
1163                         }
1164
1165                         rc = CIFSSMBRead(xid, pTcon,
1166                                 open_file->netfid,
1167                                 read_size, offset,
1168                                 &bytes_read, &smb_read_data);
1169                         /* BB need to check return code here */
1170                         if(rc== -EAGAIN) {
1171                                 if(smb_read_data) {
1172                                         cifs_buf_release(smb_read_data);
1173                                         smb_read_data = NULL;
1174                                 }
1175                         }
1176                 }
1177                 if ((rc < 0) || (smb_read_data == NULL)) {
1178                         cFYI(1,("Read error in readpages: %d",rc));
1179                         /* clean up remaing pages off list */
1180                         while (!list_empty(page_list) && (i < num_pages)) {
1181                                 page = list_entry(page_list->prev, struct page, lru);
1182                                 list_del(&page->lru);
1183                                 page_cache_release(page);
1184                         }
1185                         break;
1186                 } else if (bytes_read > 0) {
1187                         pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1188                         cifs_copy_cache_pages(mapping, page_list, bytes_read,
1189                                 smb_read_data + 4 /* RFC1001 hdr */ +
1190                                 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1191
1192                         i +=  bytes_read >> PAGE_CACHE_SHIFT;
1193 #ifdef CONFIG_CIFS_STATS
1194                         atomic_inc(&pTcon->num_reads);
1195                         spin_lock(&pTcon->stat_lock);
1196                         pTcon->bytes_read += bytes_read;
1197                         spin_unlock(&pTcon->stat_lock);
1198 #endif
1199                         if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1200                                 cFYI(1,("Partial page %d of %d read to cache",i++,num_pages));
1201
1202                                 i++; /* account for partial page */
1203
1204                                 /* server copy of file can have smaller size than client */
1205                                 /* BB do we need to verify this common case ? this case is ok - 
1206                                 if we are at server EOF we will hit it on next read */
1207
1208                         /* while(!list_empty(page_list) && (i < num_pages)) {
1209                                         page = list_entry(page_list->prev,struct page, list);
1210                                         list_del(&page->list);
1211                                         page_cache_release(page);
1212                                 }
1213                                 break; */
1214                         }
1215                 } else {
1216                         cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); 
1217                         /* BB turn off caching and do new lookup on file size at server? */
1218                         while (!list_empty(page_list) && (i < num_pages)) {
1219                                 page = list_entry(page_list->prev, struct page, lru);
1220                                 list_del(&page->lru);
1221                                 page_cache_release(page); /* BB removeme - replace with zero of page? */
1222                         }
1223                         break;
1224                 }
1225                 if(smb_read_data) {
1226                         cifs_buf_release(smb_read_data);
1227                         smb_read_data = NULL;
1228                 }
1229                 bytes_read = 0;
1230         }
1231
1232         pagevec_lru_add(&lru_pvec);
1233
1234 /* need to free smb_read_data buf before exit */
1235         if(smb_read_data) {
1236                 cifs_buf_release(smb_read_data);
1237                 smb_read_data = NULL;
1238         } 
1239
1240         FreeXid(xid);
1241         return rc;
1242 }
1243
1244 static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
1245 {
1246         char * read_data;
1247         int rc;
1248
1249         page_cache_get(page);
1250         read_data = kmap(page);
1251         /* for reads over a certain size could initiate async read ahead */
1252                                                                                                                            
1253         rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1254                                                                                                                            
1255         if (rc < 0)
1256                 goto io_error;
1257         else {
1258                 cFYI(1,("Bytes read %d ",rc));
1259         }
1260                                                                                                                            
1261         file->f_dentry->d_inode->i_atime = CURRENT_TIME;
1262                                                                                                                            
1263         if(PAGE_CACHE_SIZE > rc) {
1264                 memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
1265         }
1266         flush_dcache_page(page);
1267         SetPageUptodate(page);
1268         rc = 0;
1269                                                                                                                            
1270 io_error:
1271         kunmap(page);
1272         page_cache_release(page);
1273         return rc;
1274 }
1275
1276 static int
1277 cifs_readpage(struct file *file, struct page *page)
1278 {
1279         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1280         int rc = -EACCES;
1281         int xid;
1282
1283         xid = GetXid();
1284
1285         if (file->private_data == NULL) {
1286                 FreeXid(xid);
1287                 return -EBADF;
1288         }
1289
1290         cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
1291
1292         rc = cifs_readpage_worker(file,page,&offset);
1293
1294         unlock_page(page);
1295
1296         FreeXid(xid);
1297         return rc;
1298 }
1299
1300 /* We do not want to update the file size from server for inodes
1301    open for write - to avoid races with writepage extending
1302    the file - in the future we could consider allowing
1303    refreshing the inode only on increases in the file size 
1304    but this is tricky to do without racing with writebehind
1305    page caching in the current Linux kernel design */
1306    
1307 int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
1308 {
1309         struct list_head *tmp;
1310         struct list_head *tmp1;
1311         struct cifsFileInfo *open_file = NULL;
1312         int rc = TRUE;
1313
1314         if(cifsInode == NULL)
1315                 return rc;
1316
1317         read_lock(&GlobalSMBSeslock); 
1318         list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
1319                 open_file = list_entry(tmp,struct cifsFileInfo, flist);
1320                 if(open_file == NULL)
1321                         break;
1322                 if(open_file->closePend)
1323                         continue;
1324         /* We check if file is open for writing,   
1325         BB we could supplement this with a check to see if file size
1326         changes have been flushed to server - ie inode metadata dirty */
1327                 if((open_file->pfile) && 
1328            ((open_file->pfile->f_flags & O_RDWR) || 
1329                 (open_file->pfile->f_flags & O_WRONLY))) {
1330                          rc = FALSE;
1331                          break;
1332                 }
1333                 if(tmp->next == NULL) {
1334                         cFYI(1,("File instance %p removed",tmp));
1335                         break;
1336                 }
1337         }
1338         read_unlock(&GlobalSMBSeslock);
1339         return rc;
1340 }
1341
1342
1343 void
1344 fill_in_inode(struct inode *tmp_inode,
1345               FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
1346 {
1347         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1348         struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1349
1350         pfindData->ExtFileAttributes =
1351             le32_to_cpu(pfindData->ExtFileAttributes);
1352         pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
1353         pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
1354         cifsInfo->cifsAttrs = pfindData->ExtFileAttributes;
1355         cifsInfo->time = jiffies;
1356
1357         /* Linux can not store file creation time unfortunately so ignore it */
1358         tmp_inode->i_atime =
1359             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1360         tmp_inode->i_mtime =
1361             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
1362         tmp_inode->i_ctime =
1363             cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
1364         /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
1365         /* 2767 perms - indicate mandatory locking */
1366                 /* BB fill in uid and gid here? with help from winbind? 
1367                         or retrieve from NTFS stream extended attribute */
1368         if(atomic_read(&cifsInfo->inUse) == 0) {
1369                 tmp_inode->i_uid = cifs_sb->mnt_uid;
1370                 tmp_inode->i_gid = cifs_sb->mnt_gid;
1371                 /* set default mode. will override for dirs below */
1372                 tmp_inode->i_mode = cifs_sb->mnt_file_mode;
1373         }
1374
1375         cFYI(0,
1376              ("CIFS FFIRST: Attributes came in as 0x%x",
1377               pfindData->ExtFileAttributes));
1378         if (pfindData->ExtFileAttributes & ATTR_REPARSE) {
1379                 *pobject_type = DT_LNK;
1380                 /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */
1381                 tmp_inode->i_mode |= S_IFLNK;
1382         } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) {
1383                 *pobject_type = DT_DIR;
1384                 /* override default perms since we do not lock dirs */
1385                 if(atomic_read(&cifsInfo->inUse) == 0) {
1386                         tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
1387                 }
1388                 tmp_inode->i_mode |= S_IFDIR;
1389         } else {
1390                 *pobject_type = DT_REG;
1391                 tmp_inode->i_mode |= S_IFREG;
1392                 if(pfindData->ExtFileAttributes & ATTR_READONLY)
1393                         tmp_inode->i_mode &= ~(S_IWUGO);
1394
1395         }/* could add code here - to validate if device or weird share type? */
1396
1397         /* can not fill in nlink here as in qpathinfo version and Unx search */
1398         if(atomic_read(&cifsInfo->inUse) == 0) {
1399                 atomic_set(&cifsInfo->inUse,1);
1400         }
1401
1402         if(is_size_safe_to_change(cifsInfo)) {
1403                 /* can not safely change the file size here if the 
1404                 client is writing to it due to potential races */
1405                 i_size_write(tmp_inode,pfindData->EndOfFile);
1406
1407         /* 512 bytes (2**9) is the fake blocksize that must be used */
1408         /* for this calculation, even though the reported blocksize is larger */
1409                 tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
1410         }
1411
1412         if (pfindData->AllocationSize < pfindData->EndOfFile)
1413                 cFYI(1, ("Possible sparse file: allocation size less than end of file "));
1414         cFYI(1,
1415              ("File Size %ld and blocks %ld and blocksize %ld",
1416               (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
1417               tmp_inode->i_blksize));
1418         if (S_ISREG(tmp_inode->i_mode)) {
1419                 cFYI(1, (" File inode "));
1420                 tmp_inode->i_op = &cifs_file_inode_ops;
1421                 tmp_inode->i_fop = &cifs_file_ops;
1422                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1423         } else if (S_ISDIR(tmp_inode->i_mode)) {
1424                 cFYI(1, (" Directory inode"));
1425                 tmp_inode->i_op = &cifs_dir_inode_ops;
1426                 tmp_inode->i_fop = &cifs_dir_ops;
1427         } else if (S_ISLNK(tmp_inode->i_mode)) {
1428                 cFYI(1, (" Symbolic Link inode "));
1429                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1430         } else {
1431                 cFYI(1, (" Init special inode "));
1432                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1433                                    tmp_inode->i_rdev);
1434         }
1435 }
1436
1437 void
1438 unix_fill_in_inode(struct inode *tmp_inode,
1439                    FILE_UNIX_INFO * pfindData, int *pobject_type)
1440 {
1441         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1442         cifsInfo->time = jiffies;
1443         atomic_inc(&cifsInfo->inUse);
1444
1445         tmp_inode->i_atime =
1446             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1447         tmp_inode->i_mtime =
1448             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
1449         tmp_inode->i_ctime =
1450             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
1451
1452         tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
1453         pfindData->Type = le32_to_cpu(pfindData->Type);
1454         if (pfindData->Type == UNIX_FILE) {
1455                 *pobject_type = DT_REG;
1456                 tmp_inode->i_mode |= S_IFREG;
1457         } else if (pfindData->Type == UNIX_SYMLINK) {
1458                 *pobject_type = DT_LNK;
1459                 tmp_inode->i_mode |= S_IFLNK;
1460         } else if (pfindData->Type == UNIX_DIR) {
1461                 *pobject_type = DT_DIR;
1462                 tmp_inode->i_mode |= S_IFDIR;
1463         } else if (pfindData->Type == UNIX_CHARDEV) {
1464                 *pobject_type = DT_CHR;
1465                 tmp_inode->i_mode |= S_IFCHR;
1466                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
1467                                 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1468         } else if (pfindData->Type == UNIX_BLOCKDEV) {
1469                 *pobject_type = DT_BLK;
1470                 tmp_inode->i_mode |= S_IFBLK;
1471                 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
1472                                 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1473         } else if (pfindData->Type == UNIX_FIFO) {
1474                 *pobject_type = DT_FIFO;
1475                 tmp_inode->i_mode |= S_IFIFO;
1476         } else if (pfindData->Type == UNIX_SOCKET) {
1477                 *pobject_type = DT_SOCK;
1478                 tmp_inode->i_mode |= S_IFSOCK;
1479         }
1480
1481         tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
1482         tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
1483         tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
1484
1485         pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
1486
1487         if(is_size_safe_to_change(cifsInfo)) {
1488                 /* can not safely change the file size here if the 
1489                 client is writing to it due to potential races */
1490                 pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
1491                 i_size_write(tmp_inode,pfindData->EndOfFile);
1492
1493         /* 512 bytes (2**9) is the fake blocksize that must be used */
1494         /* for this calculation, not the real blocksize */
1495                 tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
1496         }
1497
1498         if (S_ISREG(tmp_inode->i_mode)) {
1499                 cFYI(1, ("File inode"));
1500                 tmp_inode->i_op = &cifs_file_inode_ops;
1501                 tmp_inode->i_fop = &cifs_file_ops;
1502                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1503         } else if (S_ISDIR(tmp_inode->i_mode)) {
1504                 cFYI(1, ("Directory inode"));
1505                 tmp_inode->i_op = &cifs_dir_inode_ops;
1506                 tmp_inode->i_fop = &cifs_dir_ops;
1507         } else if (S_ISLNK(tmp_inode->i_mode)) {
1508                 cFYI(1, ("Symbolic Link inode"));
1509                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1510 /* tmp_inode->i_fop = *//* do not need to set to anything */
1511         } else {
1512                 cFYI(1, ("Special inode")); 
1513                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1514                                    tmp_inode->i_rdev);
1515         }
1516 }
1517
1518 static void
1519 construct_dentry(struct qstr *qstring, struct file *file,
1520                  struct inode **ptmp_inode, struct dentry **pnew_dentry)
1521 {
1522         struct dentry *tmp_dentry;
1523         struct cifs_sb_info *cifs_sb;
1524         struct cifsTconInfo *pTcon;
1525
1526         cFYI(1, ("For %s ", qstring->name));
1527         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1528         pTcon = cifs_sb->tcon;
1529
1530         qstring->hash = full_name_hash(qstring->name, qstring->len);
1531         tmp_dentry = d_lookup(file->f_dentry, qstring);
1532         if (tmp_dentry) {
1533                 cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
1534                 *ptmp_inode = tmp_dentry->d_inode;
1535                 /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
1536                 if(*ptmp_inode == NULL) {
1537                         *ptmp_inode = new_inode(file->f_dentry->d_sb);
1538                         if(*ptmp_inode == NULL)
1539                                 return;
1540                         d_instantiate(tmp_dentry, *ptmp_inode);
1541                         insert_inode_hash(*ptmp_inode);
1542                 }
1543         } else {
1544                 tmp_dentry = d_alloc(file->f_dentry, qstring);
1545                 if(tmp_dentry == NULL) {
1546                         cERROR(1,("Failed allocating dentry"));
1547                         *ptmp_inode = NULL;
1548                         return;
1549                 }
1550                         
1551                 *ptmp_inode = new_inode(file->f_dentry->d_sb);
1552                 tmp_dentry->d_op = &cifs_dentry_ops;
1553                 if(*ptmp_inode == NULL)
1554                         return;
1555                 d_instantiate(tmp_dentry, *ptmp_inode);
1556                 d_rehash(tmp_dentry);
1557                 insert_inode_hash(*ptmp_inode);
1558         }
1559
1560         tmp_dentry->d_time = jiffies;
1561         *pnew_dentry = tmp_dentry;
1562 }
1563
1564 static void reset_resume_key(struct file * dir_file, 
1565                                 unsigned char * filename, 
1566                                 unsigned int len,int Unicode,struct nls_table * nls_tab) {
1567         struct cifsFileInfo *cifsFile;
1568
1569         cifsFile = (struct cifsFileInfo *)dir_file->private_data;
1570         if(cifsFile == NULL)
1571                 return;
1572         if(cifsFile->search_resume_name) {
1573                 kfree(cifsFile->search_resume_name);
1574         }
1575
1576         if(Unicode) 
1577                 len *= 2;
1578         cifsFile->resume_name_length = len;
1579
1580         cifsFile->search_resume_name = 
1581                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1582
1583         if(cifsFile->search_resume_name == NULL) {
1584                 cERROR(1,("failed new resume key allocate, length %d",
1585                                   cifsFile->resume_name_length));
1586                 return;
1587         }
1588         if(Unicode)
1589                 cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
1590                         filename, len, nls_tab);
1591         else
1592                 memcpy(cifsFile->search_resume_name, filename, 
1593                    cifsFile->resume_name_length);
1594         cFYI(1,("Reset resume key to: %s with len %d",filename,len));
1595         return;
1596 }
1597
1598
1599
1600 static int
1601 cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
1602              struct file *file, filldir_t filldir, void *direntry)
1603 {
1604         struct inode *tmp_inode;
1605         struct dentry *tmp_dentry;
1606         int object_type,rc;
1607
1608         pqstring->name = pfindData->FileName;
1609         pqstring->len = pfindData->FileNameLength;
1610
1611         construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1612         if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
1613                 return -ENOMEM;
1614         }
1615         fill_in_inode(tmp_inode, pfindData, &object_type);
1616         rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
1617                 tmp_inode->i_ino, object_type);
1618         if(rc) {
1619                 /* due to readdir error we need to recalculate resume 
1620                 key so next readdir will restart on right entry */
1621                 cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
1622         }
1623         dput(tmp_dentry);
1624         return rc;
1625 }
1626
1627 static int
1628 cifs_filldir_unix(struct qstr *pqstring,
1629                   FILE_UNIX_INFO * pUnixFindData, struct file *file,
1630                   filldir_t filldir, void *direntry)
1631 {
1632         struct inode *tmp_inode;
1633         struct dentry *tmp_dentry;
1634         int object_type, rc;
1635
1636         pqstring->name = pUnixFindData->FileName;
1637         pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
1638
1639         construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1640         if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
1641                 return -ENOMEM;
1642         }
1643
1644         unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
1645         rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
1646                 file->f_pos, tmp_inode->i_ino, object_type);
1647         if(rc) {
1648                 /* due to readdir error we need to recalculate resume 
1649                         key so next readdir will restart on right entry */
1650                 cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
1651         }
1652         dput(tmp_dentry);
1653         return rc;
1654 }
1655
1656 int
1657 cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
1658 {
1659         int rc = 0;
1660         int xid;
1661         int Unicode = FALSE;
1662         int UnixSearch = FALSE;
1663         unsigned int bufsize, i;
1664         __u16 searchHandle;
1665         struct cifs_sb_info *cifs_sb;
1666         struct cifsTconInfo *pTcon;
1667         struct cifsFileInfo *cifsFile = NULL;
1668         char *full_path = NULL;
1669         char *data;
1670         struct qstr qstring;
1671         T2_FFIRST_RSP_PARMS findParms;
1672         T2_FNEXT_RSP_PARMS findNextParms;
1673         FILE_DIRECTORY_INFO *pfindData;
1674         FILE_DIRECTORY_INFO *lastFindData;
1675         FILE_UNIX_INFO *pfindDataUnix;
1676
1677         xid = GetXid();
1678
1679         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1680         pTcon = cifs_sb->tcon;
1681         bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
1682         if(bufsize > CIFS_MAX_MSGSIZE) {
1683                 FreeXid(xid);
1684                 return -EIO;
1685         }
1686         data = kmalloc(bufsize, GFP_KERNEL);
1687         pfindData = (FILE_DIRECTORY_INFO *) data;
1688
1689         if(file->f_dentry == NULL) {
1690                 FreeXid(xid);
1691                 return -EIO;
1692         }
1693         down(&file->f_dentry->d_sb->s_vfs_rename_sem);
1694         full_path = build_wildcard_path_from_dentry(file->f_dentry);
1695         up(&file->f_dentry->d_sb->s_vfs_rename_sem);
1696
1697
1698         cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
1699
1700         switch ((int) file->f_pos) {
1701         case 0:
1702                 if (filldir(direntry, ".", 1, file->f_pos,
1703                      file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
1704                         cERROR(1, ("Filldir for current dir failed "));
1705                         break;
1706                 }
1707                 file->f_pos++;
1708                 /* fallthrough */
1709         case 1:
1710                 if (filldir(direntry, "..", 2, file->f_pos,
1711                      file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1712                         cERROR(1, ("Filldir for parent dir failed "));
1713                         break;
1714                 }
1715                 file->f_pos++;
1716                 /* fallthrough */
1717         case 2:
1718                 if (file->private_data != NULL) {
1719                         cifsFile =
1720                                 (struct cifsFileInfo *) file->private_data;
1721                         if (cifsFile->endOfSearch) {
1722                                 if(cifsFile->emptyDir) {
1723                                         cFYI(1, ("End of search, empty dir"));
1724                                         rc = 0;
1725                                         break;
1726                                 }
1727                         } else {
1728                                 cifsFile->invalidHandle = TRUE;
1729                                 CIFSFindClose(xid, pTcon, cifsFile->netfid);
1730                         }
1731                         if(cifsFile->search_resume_name) {
1732                                 kfree(cifsFile->search_resume_name);
1733                                 cifsFile->search_resume_name = NULL;
1734                         }
1735                 }
1736                 rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
1737                                 &findParms, cifs_sb->local_nls,
1738                                 &Unicode, &UnixSearch);
1739                 cFYI(1, ("Count: %d  End: %d ", findParms.SearchCount,
1740                         findParms.EndofSearch));
1741  
1742                 if (rc == 0) {
1743                         searchHandle = findParms.SearchHandle;
1744                         if(file->private_data == NULL)
1745                                 file->private_data =
1746                                         kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
1747                         if (file->private_data) {
1748                                 memset(file->private_data, 0,
1749                                        sizeof (struct cifsFileInfo));
1750                                 cifsFile =
1751                                     (struct cifsFileInfo *) file->private_data;
1752                                 cifsFile->netfid = searchHandle;
1753                                 cifsFile->invalidHandle = FALSE;
1754                                 init_MUTEX(&cifsFile->fh_sem);
1755                         } else {
1756                                 rc = -ENOMEM;
1757                                 break;
1758                         }
1759
1760                         renew_parental_timestamps(file->f_dentry);
1761                         lastFindData = 
1762                                 (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
1763                                         findParms.LastNameOffset);
1764                         if((char *)lastFindData > (char *)pfindData + bufsize) {
1765                                 cFYI(1,("last search entry past end of packet"));
1766                                 rc = -EIO;
1767                                 break;
1768                         }
1769                         /* Offset of resume key same for levels 257 and 514 */
1770                         cifsFile->resume_key = lastFindData->FileIndex;
1771                         if(UnixSearch == FALSE) {
1772                                 cifsFile->resume_name_length = 
1773                                         le32_to_cpu(lastFindData->FileNameLength);
1774                                 if(cifsFile->resume_name_length > bufsize - 64) {
1775                                         cFYI(1,("Illegal resume file name length %d",
1776                                                 cifsFile->resume_name_length));
1777                                         rc = -ENOMEM;
1778                                         break;
1779                                 }
1780                                 cifsFile->search_resume_name = 
1781                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1782                                 cFYI(1,("Last file: %s with name %d bytes long",
1783                                         lastFindData->FileName,
1784                                         cifsFile->resume_name_length));
1785                                 memcpy(cifsFile->search_resume_name,
1786                                         lastFindData->FileName, 
1787                                         cifsFile->resume_name_length);
1788                         } else {
1789                                 pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
1790                                 if (Unicode == TRUE) {
1791                                         for(i=0;(pfindDataUnix->FileName[i] 
1792                                                     | pfindDataUnix->FileName[i+1]);
1793                                                 i+=2) {
1794                                                 if(i > bufsize-64)
1795                                                         break;
1796                                         }
1797                                         cifsFile->resume_name_length = i + 2;
1798                                 } else {
1799                                         cifsFile->resume_name_length = 
1800                                                 strnlen(pfindDataUnix->FileName,
1801                                                         bufsize-63);
1802                                 }
1803                                 if(cifsFile->resume_name_length > bufsize - 64) {
1804                                         cFYI(1,("Illegal resume file name length %d",
1805                                                 cifsFile->resume_name_length));
1806                                         rc = -ENOMEM;
1807                                         break;
1808                                 }
1809                                 cifsFile->search_resume_name = 
1810                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1811                                 cFYI(1,("Last file: %s with name %d bytes long",
1812                                         pfindDataUnix->FileName,
1813                                         cifsFile->resume_name_length));
1814                                 memcpy(cifsFile->search_resume_name,
1815                                         pfindDataUnix->FileName, 
1816                                         cifsFile->resume_name_length);
1817                         }
1818                         for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) {
1819                                 if (UnixSearch == FALSE) {
1820                                         pfindData->FileNameLength =
1821                                           le32_to_cpu(pfindData->FileNameLength);
1822                                         if (Unicode == TRUE)
1823                                                 pfindData->FileNameLength =
1824                                                     cifs_strfromUCS_le
1825                                                     (pfindData->FileName,
1826                                                      (wchar_t *)
1827                                                      pfindData->FileName,
1828                                                      (pfindData->
1829                                                       FileNameLength) / 2,
1830                                                      cifs_sb->local_nls);
1831                                         qstring.len = pfindData->FileNameLength;
1832                                         if (((qstring.len != 1)
1833                                              || (pfindData->FileName[0] != '.'))
1834                                             && ((qstring.len != 2)
1835                                                 || (pfindData->
1836                                                     FileName[0] != '.')
1837                                                 || (pfindData->
1838                                                     FileName[1] != '.'))) {
1839                                                 if(cifs_filldir(&qstring,
1840                                                              pfindData,
1841                                                              file, filldir,
1842                                                              direntry)) {
1843                                                         /* do not end search if
1844                                                                 kernel not ready to take
1845                                                                 remaining entries yet */
1846                                                         reset_resume_key(file, pfindData->FileName,qstring.len,
1847                                                                 Unicode, cifs_sb->local_nls);
1848                                                         findParms.EndofSearch = 0;
1849                                                         break;
1850                                                 }
1851                                                 file->f_pos++;
1852                                         }
1853                                 } else {        /* UnixSearch */
1854                                         pfindDataUnix =
1855                                             (FILE_UNIX_INFO *) pfindData;
1856                                         if (Unicode == TRUE)
1857                                                 qstring.len =
1858                                                         cifs_strfromUCS_le
1859                                                         (pfindDataUnix->FileName,
1860                                                         (wchar_t *)
1861                                                         pfindDataUnix->FileName,
1862                                                         MAX_PATHCONF,
1863                                                         cifs_sb->local_nls);
1864                                         else
1865                                                 qstring.len =
1866                                                         strnlen(pfindDataUnix->
1867                                                           FileName,
1868                                                           MAX_PATHCONF);
1869                                         if (((qstring.len != 1)
1870                                              || (pfindDataUnix->
1871                                                  FileName[0] != '.'))
1872                                             && ((qstring.len != 2)
1873                                                 || (pfindDataUnix->
1874                                                     FileName[0] != '.')
1875                                                 || (pfindDataUnix->
1876                                                     FileName[1] != '.'))) {
1877                                                 if(cifs_filldir_unix(&qstring,
1878                                                                   pfindDataUnix,
1879                                                                   file,
1880                                                                   filldir,
1881                                                                   direntry)) {
1882                                                         /* do not end search if
1883                                                                 kernel not ready to take
1884                                                                 remaining entries yet */
1885                                                         findParms.EndofSearch = 0;
1886                                                         reset_resume_key(file, pfindDataUnix->FileName,
1887                                                                 qstring.len,Unicode,cifs_sb->local_nls);
1888                                                         break;
1889                                                 }
1890                                                 file->f_pos++;
1891                                         }
1892                                 }
1893                                 /* works also for Unix ff struct since first field of both */
1894                                 pfindData = 
1895                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData
1896                                                  + le32_to_cpu(pfindData->NextEntryOffset));
1897                                 /* BB also should check to make sure that pointer is not beyond the end of the SMB */
1898                                 /* if(pfindData > lastFindData) rc = -EIO; break; */
1899                         }       /* end for loop */
1900                         if ((findParms.EndofSearch != 0) && cifsFile) {
1901                                 cifsFile->endOfSearch = TRUE;
1902                                 if(findParms.SearchCount == 2)
1903                                         cifsFile->emptyDir = TRUE;
1904                         }
1905                 } else {
1906                         if (cifsFile)
1907                                 cifsFile->endOfSearch = TRUE;
1908                         /* unless parent directory gone do not return error */
1909                         rc = 0;
1910                 }
1911                 break;
1912         default:
1913                 if (file->private_data == NULL) {
1914                         rc = -EBADF;
1915                         cFYI(1,
1916                              ("Readdir on closed srch, pos = %lld",
1917                               file->f_pos));
1918                 } else {
1919                         cifsFile = (struct cifsFileInfo *) file->private_data;
1920                         if (cifsFile->endOfSearch) {
1921                                 rc = 0;
1922                                 cFYI(1, ("End of search "));
1923                                 break;
1924                         }
1925                         searchHandle = cifsFile->netfid;
1926                         rc = CIFSFindNext(xid, pTcon, pfindData,
1927                                 &findNextParms, searchHandle, 
1928                                 cifsFile->search_resume_name,
1929                                 cifsFile->resume_name_length,
1930                                 cifsFile->resume_key,
1931                                 &Unicode, &UnixSearch);
1932                         cFYI(1,("Count: %d  End: %d ",
1933                               findNextParms.SearchCount,
1934                               findNextParms.EndofSearch));
1935                         if ((rc == 0) && (findNextParms.SearchCount != 0)) {
1936                         /* BB save off resume key, key name and name length  */
1937                                 lastFindData = 
1938                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData 
1939                                                 + findNextParms.LastNameOffset);
1940                                 if((char *)lastFindData > (char *)pfindData + bufsize) {
1941                                         cFYI(1,("last search entry past end of packet"));
1942                                         rc = -EIO;
1943                                         break;
1944                                 }
1945                                 /* Offset of resume key same for levels 257 and 514 */
1946                                 cifsFile->resume_key = lastFindData->FileIndex;
1947
1948                                 if(UnixSearch == FALSE) {
1949                                         cifsFile->resume_name_length = 
1950                                                 le32_to_cpu(lastFindData->FileNameLength);
1951                                         if(cifsFile->resume_name_length > bufsize - 64) {
1952                                                 cFYI(1,("Illegal resume file name length %d",
1953                                                         cifsFile->resume_name_length));
1954                                                 rc = -ENOMEM;
1955                                                 break;
1956                                         }
1957                                         /* Free the memory allocated by previous findfirst 
1958                                         or findnext call - we can not reuse the memory since
1959                                         the resume name may not be same string length */
1960                                         if(cifsFile->search_resume_name)
1961                                                 kfree(cifsFile->search_resume_name);
1962                                         cifsFile->search_resume_name = 
1963                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1964                                         cFYI(1,("Last file: %s with name %d bytes long",
1965                                                 lastFindData->FileName,
1966                                                 cifsFile->resume_name_length));
1967                                         memcpy(cifsFile->search_resume_name,
1968                                                 lastFindData->FileName, 
1969                                                 cifsFile->resume_name_length);
1970                                 } else {
1971                                         pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
1972                                         if (Unicode == TRUE) {
1973                                                 for(i=0;(pfindDataUnix->FileName[i] 
1974                                                                 | pfindDataUnix->FileName[i+1]);
1975                                                         i+=2) {
1976                                                         if(i > bufsize-64)
1977                                                                 break;
1978                                                 }
1979                                                 cifsFile->resume_name_length = i + 2;
1980                                         } else {
1981                                                 cifsFile->resume_name_length = 
1982                                                         strnlen(pfindDataUnix->
1983                                                          FileName,
1984                                                          MAX_PATHCONF);
1985                                         }
1986                                         if(cifsFile->resume_name_length > bufsize - 64) {
1987                                                 cFYI(1,("Illegal resume file name length %d",
1988                                                                 cifsFile->resume_name_length));
1989                                                 rc = -ENOMEM;
1990                                                 break;
1991                                         }
1992                                         /* Free the memory allocated by previous findfirst 
1993                                         or findnext call - we can not reuse the memory since
1994                                         the resume name may not be same string length */
1995                                         if(cifsFile->search_resume_name)
1996                                                 kfree(cifsFile->search_resume_name);
1997                                         cifsFile->search_resume_name = 
1998                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1999                                         cFYI(1,("fnext last file: %s with name %d bytes long",
2000                                                 pfindDataUnix->FileName,
2001                                                 cifsFile->resume_name_length));
2002                                         memcpy(cifsFile->search_resume_name,
2003                                                 pfindDataUnix->FileName, 
2004                                                 cifsFile->resume_name_length);
2005                                 }
2006
2007                                 for (i = 0; i < findNextParms.SearchCount; i++) {
2008                                         pfindData->FileNameLength =
2009                                             le32_to_cpu(pfindData->
2010                                                         FileNameLength);
2011                                         if (UnixSearch == FALSE) {
2012                                                 if (Unicode == TRUE)
2013                                                         pfindData->FileNameLength =
2014                                                           cifs_strfromUCS_le
2015                                                           (pfindData->FileName,
2016                                                           (wchar_t *)
2017                                                           pfindData->FileName,
2018                                                           (pfindData->FileNameLength)/ 2,
2019                                                           cifs_sb->local_nls);
2020                                                 qstring.len = 
2021                                                         pfindData->FileNameLength;
2022                                                 if (((qstring.len != 1)
2023                                                     || (pfindData->FileName[0] != '.'))
2024                                                     && ((qstring.len != 2)
2025                                                         || (pfindData->FileName[0] != '.')
2026                                                         || (pfindData->FileName[1] !=
2027                                                             '.'))) {
2028                                                         if(cifs_filldir
2029                                                             (&qstring,
2030                                                              pfindData,
2031                                                              file, filldir,
2032                                                              direntry)) {
2033                                                         /* do not end search if
2034                                                                 kernel not ready to take
2035                                                                 remaining entries yet */
2036                                                                 findNextParms.EndofSearch = 0;
2037                                                                 reset_resume_key(file, pfindData->FileName,qstring.len,
2038                                                                         Unicode,cifs_sb->local_nls);
2039                                                                 break;
2040                                                         }
2041                                                         file->f_pos++;
2042                                                 }
2043                                         } else {        /* UnixSearch */
2044                                                 pfindDataUnix =
2045                                                     (FILE_UNIX_INFO *)
2046                                                     pfindData;
2047                                                 if (Unicode == TRUE)
2048                                                         qstring.len =
2049                                                           cifs_strfromUCS_le
2050                                                           (pfindDataUnix->FileName,
2051                                                           (wchar_t *)
2052                                                           pfindDataUnix->FileName,
2053                                                           MAX_PATHCONF,
2054                                                           cifs_sb->local_nls);
2055                                                 else
2056                                                         qstring.len =
2057                                                           strnlen
2058                                                           (pfindDataUnix->
2059                                                           FileName,
2060                                                           MAX_PATHCONF);
2061                                                 if (((qstring.len != 1)
2062                                                      || (pfindDataUnix->
2063                                                          FileName[0] != '.'))
2064                                                     && ((qstring.len != 2)
2065                                                         || (pfindDataUnix->
2066                                                             FileName[0] != '.')
2067                                                         || (pfindDataUnix->
2068                                                             FileName[1] !=
2069                                                             '.'))) {
2070                                                         if(cifs_filldir_unix
2071                                                             (&qstring,
2072                                                              pfindDataUnix,
2073                                                              file, filldir,
2074                                                              direntry)) {
2075                                                                 /* do not end search if
2076                                                                 kernel not ready to take
2077                                                                 remaining entries yet */
2078                                                                 findNextParms.EndofSearch = 0;
2079                                                                 reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
2080                                                                         Unicode,cifs_sb->local_nls);
2081                                                                 break;
2082                                                         }
2083                                                         file->f_pos++;
2084                                                 }
2085                                         }
2086                                         pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
2087                                                 le32_to_cpu(pfindData->NextEntryOffset));
2088         /* works also for Unix find struct since first field of both */
2089         /* BB also should check to ensure pointer not beyond end of SMB */
2090                                 } /* end for loop */
2091                                 if (findNextParms.EndofSearch != 0) {
2092                                         cifsFile->endOfSearch = TRUE;
2093                                 }
2094                         } else {
2095                                 cifsFile->endOfSearch = TRUE;
2096                                 rc = 0; /* unless parent directory disappeared - do not
2097                                 return error here (eg Access Denied or no more files) */
2098                         }
2099                 }
2100         } /* end switch */
2101         if (data)
2102                 kfree(data);
2103         if (full_path)
2104                 kfree(full_path);
2105         FreeXid(xid);
2106
2107         return rc;
2108 }
2109 int cifs_prepare_write(struct file *file, struct page *page,
2110                         unsigned from, unsigned to)
2111 {
2112         int rc = 0;
2113         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2114         cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
2115         if (!PageUptodate(page)) {
2116         /*      if (to - from != PAGE_CACHE_SIZE) {
2117                         void *kaddr = kmap_atomic(page, KM_USER0);
2118                         memset(kaddr, 0, from);
2119                         memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
2120                         flush_dcache_page(page);
2121                         kunmap_atomic(kaddr, KM_USER0);
2122                 } */
2123                 /* If we are writing a full page it will be up to date,
2124                 no need to read from the server */
2125                 if((to==PAGE_CACHE_SIZE) && (from == 0))
2126                         SetPageUptodate(page);
2127
2128                 /* might as well read a page, it is fast enough */
2129                 if((file->f_flags & O_ACCMODE) != O_WRONLY) {
2130                         rc = cifs_readpage_worker(file,page,&offset);
2131                 } else {
2132                 /* should we try using another
2133                 file handle if there is one - how would we lock it
2134                 to prevent close of that handle racing with this read? */
2135                 /* In any case this will be written out by commit_write */
2136                 }
2137         }
2138
2139         /* BB should we pass any errors back? e.g. if we do not have read access to the file */
2140         return 0;
2141 }
2142
2143
2144 struct address_space_operations cifs_addr_ops = {
2145         .readpage = cifs_readpage,
2146         .readpages = cifs_readpages,
2147         .writepage = cifs_writepage,
2148         .prepare_write = cifs_prepare_write, 
2149         .commit_write = cifs_commit_write,
2150         .set_page_dirty = __set_page_dirty_nobuffers,
2151    /* .sync_page = cifs_sync_page, */
2152         /*.direct_IO = */
2153 };