file.c 68.4 KB
Newer Older
1 2 3 4 5
/*
 *   fs/cifs/file.c
 *
 *   vfs operations that deal with files
 * 
6
 *   Copyright (C) International Business Machines  Corp., 2002,2003
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/pagemap.h>
27
#include <linux/pagevec.h>
28 29 30 31 32 33 34 35 36 37
#include <linux/smp_lock.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"

38 39
extern int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir); /* BB removeme BB */

40 41 42 43 44 45 46
int
cifs_open(struct inode *inode, struct file *file)
{
	int rc = -EACCES;
	int xid, oplock;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
47 48
	struct cifsFileInfo *pCifsFile;
	struct cifsInodeInfo *pCifsInode;
49
	struct list_head * tmp;
50 51
	char *full_path = NULL;
	int desiredAccess = 0x20197;
52
	int disposition;
53
	__u16 netfid;
54
	FILE_ALL_INFO * buf = NULL;
55 56 57 58 59 60

	xid = GetXid();

	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;

61
	if (file->f_flags & O_CREAT) {
62 63 64 65 66
		/* search inode for this file and fill in file->private_data = */
		pCifsInode = CIFS_I(file->f_dentry->d_inode);
		read_lock(&GlobalSMBSeslock);
		list_for_each(tmp, &pCifsInode->openFileList) {            
			pCifsFile = list_entry(tmp,struct cifsFileInfo, flist);           
67
			if((pCifsFile->pfile == NULL)&& (pCifsFile->pid == current->tgid)){
68
			/* mode set in cifs_create */
69 70 71 72 73 74 75 76 77 78 79 80 81
				pCifsFile->pfile = file; /* needed for writepage */
				file->private_data = pCifsFile;
				break;
			}
		}
		read_unlock(&GlobalSMBSeslock);
		if(file->private_data != NULL) {
			rc = 0;
			FreeXid(xid);
			return rc;
		} else {
			if(file->f_flags & O_EXCL)
				cERROR(1,("could not find file instance for new file %p ",file));
82 83 84
		}
	}

85
	down(&inode->i_sb->s_vfs_rename_sem);
86
	full_path = build_path_from_dentry(file->f_dentry);
87
	up(&inode->i_sb->s_vfs_rename_sem);
88 89 90 91
	if(full_path == NULL) {
		FreeXid(xid);
		return -ENOMEM;
	}
92

93
	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
94 95 96 97
	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
		desiredAccess = GENERIC_READ;
	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
		desiredAccess = GENERIC_WRITE;
98 99 100 101 102 103
	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
		/* GENERIC_ALL is too much permission to request */
		/* can cause unnecessary access denied on create */
		/* desiredAccess = GENERIC_ALL; */
		desiredAccess = GENERIC_READ | GENERIC_WRITE;
	}
104

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
/*********************************************************************
 *  open flag mapping table:
 *  
 *	POSIX Flag            CIFS Disposition
 *	----------            ---------------- 
 *	O_CREAT               FILE_OPEN_IF
 *	O_CREAT | O_EXCL      FILE_CREATE
 *	O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
 *	O_TRUNC               FILE_OVERWRITE
 *	none of the above     FILE_OPEN
 *
 *	Note that there is not a direct match between disposition
 *	FILE_SUPERSEDE (ie create whether or not file exists although 
 *	O_CREAT | O_TRUNC is similar but truncates the existing
 *	file rather than creating a new file as FILE_SUPERSEDE does
 *	(which uses the attributes / metadata passed in on open call)
 *?
 *?  O_SYNC is a reasonable match to CIFS writethrough flag  
 *?  and the read write flags match reasonably.  O_LARGEFILE
 *?  is irrelevant because largefile support is always used
 *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
 *	 O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
 *********************************************************************/

	if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
		disposition = FILE_CREATE;
	else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
		disposition = FILE_OVERWRITE_IF;
	else if((file->f_flags & O_CREAT) == O_CREAT)
		disposition = FILE_OPEN_IF;
	else
		disposition = FILE_OPEN;
137 138

	if (oplockEnabled)
139
		oplock = REQ_OPLOCK;
140 141 142 143
	else
		oplock = FALSE;

	/* BB pass O_SYNC flag through on file attributes .. BB */
144

145
	/* Also refresh inode by passing in file_info buf returned by SMBOpen 
146 147
	   and calling get_inode_info with returned buf (at least 
	   helps non-Unix server case */
148 149 150 151

	/* BB we can not do this if this is the second open of a file 
	and the first handle has writebehind data, we might be 
	able to simply do a filemap_fdatawrite/filemap_fdatawait first */
152
	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
153
	if(buf== NULL) {
154 155 156 157 158
		if (full_path)
			kfree(full_path);
		FreeXid(xid);
		return -ENOMEM;
	}
159
	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
160
			CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
161
	if (rc) {
162
		cFYI(1, ("cifs_open returned 0x%x ", rc));
163
		cFYI(1, ("oplock: %d ", oplock));	
164 165
	} else {
		file->private_data =
166
			kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
167
		if (file->private_data) {
168
			memset(file->private_data, 0, sizeof(struct cifsFileInfo));
169
			pCifsFile = (struct cifsFileInfo *) file->private_data;
170
			pCifsFile->netfid = netfid;
171
			pCifsFile->pid = current->tgid;
172
			init_MUTEX(&pCifsFile->fh_sem);
173
			pCifsFile->pfile = file; /* needed for writepage */
174
			pCifsFile->pInode = inode;
175
			pCifsFile->invalidHandle = FALSE;
176
			pCifsFile->closePend     = FALSE;
177 178
			write_lock(&file->f_owner.lock);
			write_lock(&GlobalSMBSeslock);
179 180
			list_add(&pCifsFile->tlist,&pTcon->openFileList);
			pCifsInode = CIFS_I(file->f_dentry->d_inode);
181
			if(pCifsInode) {
182 183 184 185 186 187 188 189
				/* want handles we can use to read with first */
				/* in the list so we do not have to walk the */
				/* list to search for one in prepare_write */
				if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
					list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
				} else {
					list_add(&pCifsFile->flist,&pCifsInode->openFileList);
				}
190 191
				write_unlock(&GlobalSMBSeslock);
				write_unlock(&file->f_owner.lock);
192 193 194 195 196 197
				if(pCifsInode->clientCanCacheRead) {
					/* we have the inode open somewhere else
					   no need to discard cache data */
				} else {
					if(buf) {
					/* BB need same check in cifs_create too? */
198

199 200 201 202 203
					/* if not oplocked, invalidate inode pages if mtime 
					   or file size changed */
						struct timespec temp;
						temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
						if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && 
204
							(file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
205 206
							cFYI(1,("inode unchanged on server"));
						} else {
207 208 209 210 211 212
							if(file->f_dentry->d_inode->i_mapping) {
							/* BB no need to lock inode until after invalidate*/
							/* since namei code should already have it locked?*/
								filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
								filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
							}
213 214 215 216 217 218
							cFYI(1,("invalidating remote inode since open detected it changed"));
							invalidate_remote_inode(file->f_dentry->d_inode);
						}
					}
				}
				if (pTcon->ses->capabilities & CAP_UNIX)
219
					rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
220
						full_path, inode->i_sb,xid);
221 222
				else
					rc = cifs_get_inode_info(&file->f_dentry->d_inode,
223
						full_path, buf, inode->i_sb,xid);
224

225
				if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
226 227 228
					pCifsInode->clientCanCacheAll = TRUE;
					pCifsInode->clientCanCacheRead = TRUE;
					cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
229
				} else if((oplock & 0xF) == OPLOCK_READ)
230
					pCifsInode->clientCanCacheRead = TRUE;
231 232 233
			} else {
				write_unlock(&GlobalSMBSeslock);
				write_unlock(&file->f_owner.lock);
234
			}
235
			if(oplock & CIFS_CREATE_ACTION) {           
236 237 238 239
				/* time to set mode which we can not set earlier due
				 to problems creating new read-only files */
				if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
					CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
240 241
						(__u64)-1, 
						(__u64)-1,
Steve French's avatar
Steve French committed
242
						0 /* dev */,
243 244 245 246 247 248 249
						cifs_sb->local_nls);
				else {/* BB implement via Windows security descriptors */
			/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
			/* in the meantime could set r/o dos attribute when perms are eg:
					mode & 0222 == 0 */
				}
			}
250 251 252
		}
	}

253 254
	if (buf)
		kfree(buf);
255 256 257 258 259 260
	if (full_path)
		kfree(full_path);
	FreeXid(xid);
	return rc;
}

261 262
/* Try to reaquire byte range locks that were released when session */
/* to server was lost */
263
static int cifs_relock_file(struct cifsFileInfo * cifsFile)
264 265 266
{
	int rc = 0;

267 268
/* BB list all locks open on this file and relock */

269 270 271
	return rc;
}

272
static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
273
{
274 275 276 277 278 279 280 281 282 283
	int rc = -EACCES;
	int xid, oplock;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *pCifsFile;
	struct cifsInodeInfo *pCifsInode;
	char *full_path = NULL;
	int desiredAccess = 0x20197;
	int disposition = FILE_OPEN;
	__u16 netfid;
284

285 286 287 288 289 290
	if(inode == NULL)
		return -EBADF;
	if (file->private_data) {
		pCifsFile = (struct cifsFileInfo *) file->private_data;
	} else
		return -EBADF;
291

292
	xid = GetXid();
293
	down(&pCifsFile->fh_sem);
294
	if(pCifsFile->invalidHandle == FALSE) {
295
		up(&pCifsFile->fh_sem);
296 297 298
		FreeXid(xid);
		return 0;
	}
299

300 301 302 303 304 305
	if(file->f_dentry == NULL) {
		up(&pCifsFile->fh_sem);
		cFYI(1,("failed file reopen, no valid name if dentry freed"));
		FreeXid(xid);
		return -EBADF;
	}
306 307
	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;
308 309 310 311
/* can not grab rename sem here because various ops, including
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
312
	full_path = build_path_from_dentry(file->f_dentry);
313 314 315 316 317
	if(full_path == NULL) {
		up(&pCifsFile->fh_sem);
		FreeXid(xid);
		return -ENOMEM;
	}
318

319 320 321 322 323
	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
		desiredAccess = GENERIC_READ;
	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
		desiredAccess = GENERIC_WRITE;
324 325 326 327 328 329
	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
		/* GENERIC_ALL is too much permission to request */
		/* can cause unnecessary access denied on create */
		/* desiredAccess = GENERIC_ALL; */
		desiredAccess = GENERIC_READ | GENERIC_WRITE;
	}
330 331 332 333 334 335

	if (oplockEnabled)
		oplock = REQ_OPLOCK;
	else
		oplock = FALSE;

336 337 338 339 340 341
	
	/* Can not refresh inode by passing in file_info buf to be returned
	 by SMBOpen and then calling get_inode_info with returned buf 
	 since file might have write behind data that needs to be flushed 
	 and server version of file size can be stale. If we 
	 knew for sure that inode was not dirty locally we could do this */
342

343
/*	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
344
	if(buf==0) {
345
		up(&pCifsFile->fh_sem);
346 347 348 349
		if (full_path)
			kfree(full_path);
		FreeXid(xid);
		return -ENOMEM;
350
	}*/
351
	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
352
				CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
353
	if (rc) {
354
		up(&pCifsFile->fh_sem);
355 356 357 358 359
		cFYI(1, ("cifs_open returned 0x%x ", rc));
		cFYI(1, ("oplock: %d ", oplock));
	} else {
		pCifsFile->netfid = netfid;
		pCifsFile->invalidHandle = FALSE;
360
		up(&pCifsFile->fh_sem);
361
		pCifsInode = CIFS_I(inode);
362
		if(pCifsInode) {
363 364 365
			if(can_flush) {
				filemap_fdatawrite(inode->i_mapping);
				filemap_fdatawait(inode->i_mapping);
366 367
			/* temporarily disable caching while we
			go to server to get inode info */
368 369 370 371
				pCifsInode->clientCanCacheAll = FALSE;
				pCifsInode->clientCanCacheRead = FALSE;
				if (pTcon->ses->capabilities & CAP_UNIX)
					rc = cifs_get_inode_info_unix(&inode,
372
						full_path, inode->i_sb,xid);
373 374
				else
					rc = cifs_get_inode_info(&inode,
375
						full_path, NULL, inode->i_sb,xid);
376 377 378 379 380 381
			} /* else we are writing out data to server already
			and could deadlock if we tried to flush data, and 
			since we do not know if we have data that would
			invalidate the current end of file on the server
			we can not go to the server to get the new
			inod info */
382
			if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
383 384 385
				pCifsInode->clientCanCacheAll =  TRUE;
				pCifsInode->clientCanCacheRead = TRUE;
				cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
386
			} else if((oplock & 0xF) == OPLOCK_READ) {
387 388
				pCifsInode->clientCanCacheRead = TRUE;
				pCifsInode->clientCanCacheAll =  FALSE;
389
			} else {
390 391
				pCifsInode->clientCanCacheRead = FALSE;
				pCifsInode->clientCanCacheAll =  FALSE;
392
			}
393
			cifs_relock_file(pCifsFile);
394
		}
395
	}
396 397 398 399

	if (full_path)
		kfree(full_path);
	FreeXid(xid);
400 401 402
	return rc;
}

403 404 405 406 407 408 409 410
int
cifs_close(struct inode *inode, struct file *file)
{
	int rc = 0;
	int xid;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *pSMBFile =
411
		(struct cifsFileInfo *) file->private_data;
412 413 414 415 416

	xid = GetXid();

	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;
417
	if (pSMBFile) {
418
		pSMBFile->closePend    = TRUE;
419
		write_lock(&file->f_owner.lock);
420 421 422 423 424 425 426 427 428
		if(pTcon) {
			/* no sense reconnecting to close a file that is
				already closed */
			if (pTcon->tidStatus != CifsNeedReconnect) {
				write_unlock(&file->f_owner.lock);
				rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
				write_lock(&file->f_owner.lock);
			}
		}
429
		list_del(&pSMBFile->flist);
430
		list_del(&pSMBFile->tlist);
431
		write_unlock(&file->f_owner.lock);
432 433
		if(pSMBFile->search_resume_name)
			kfree(pSMBFile->search_resume_name);
434 435 436 437 438
		kfree(file->private_data);
		file->private_data = NULL;
	} else
		rc = -EBADF;

439 440 441 442 443 444 445
	if(list_empty(&(CIFS_I(inode)->openFileList))) {
		cFYI(1,("closing last open instance for inode %p",inode));
		/* if the file is not open we do not know if we can cache
		info on this inode, much less write behind and read ahead */
		CIFS_I(inode)->clientCanCacheRead = FALSE;
		CIFS_I(inode)->clientCanCacheAll  = FALSE;
	}
446 447
	if((rc ==0) && CIFS_I(inode)->write_behind_rc)
		rc = CIFS_I(inode)->write_behind_rc;
448 449 450 451 452 453 454 455 456
	FreeXid(xid);
	return rc;
}

int
cifs_closedir(struct inode *inode, struct file *file)
{
	int rc = 0;
	int xid;
457
	struct cifsFileInfo *pCFileStruct =
458
	    (struct cifsFileInfo *) file->private_data;
459
	char * ptmp;
460

461
	cFYI(1, ("Closedir inode = 0x%p with ", inode));
462 463 464

	xid = GetXid();

465 466 467 468 469
	if (pCFileStruct) {
		struct cifsTconInfo *pTcon;
		struct cifs_sb_info * cifs_sb = CIFS_SB(file->f_dentry->d_sb);

		pTcon = cifs_sb->tcon;
470

471
		cFYI(1, ("Freeing private data in close dir"));
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		if(pCFileStruct->srch_inf.endOfSearch == FALSE) {
			pCFileStruct->invalidHandle = TRUE;
			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
			cFYI(1,("Closing uncompleted readdir with rc %d",rc));
			/* not much we can do if it fails anywway, ignore rc */
			rc = 0;
		}
		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
		if(ptmp) {
			cFYI(1,("freeing smb buf in srch struct in closedir")); /* BB removeme BB */
			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
			cifs_buf_release(ptmp);
		}
		ptmp = pCFileStruct->search_resume_name;
		if(ptmp) {
			cFYI(1,("freeing resume name in closedir")); /* BB removeme BB */
			pCFileStruct->search_resume_name = NULL;
			kfree(ptmp);
		}
491 492 493
		kfree(file->private_data);
		file->private_data = NULL;
	}
494
	/* BB can we lock the filestruct while this is going on? */
495 496 497 498 499 500 501 502 503 504 505 506
	FreeXid(xid);
	return rc;
}

int
cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
{
	int rc, xid;
	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
	__u32 numLock = 0;
	__u32 numUnlock = 0;
	__u64 length;
507
	int wait_flag = FALSE;
508 509 510 511 512 513 514 515 516
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	length = 1 + pfLock->fl_end - pfLock->fl_start;

	rc = -EACCES;

	xid = GetXid();

	cFYI(1,
517
	     ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
518 519 520 521
	      cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
	      pfLock->fl_end));

	if (pfLock->fl_flags & FL_POSIX)
522
		cFYI(1, ("Posix "));
523
	if (pfLock->fl_flags & FL_FLOCK)
524
		cFYI(1, ("Flock "));
525
	if (pfLock->fl_flags & FL_SLEEP) {
526
		cFYI(1, ("Blocking lock "));
527 528
		wait_flag = TRUE;
	}
529
	if (pfLock->fl_flags & FL_ACCESS)
530
		cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
531
	if (pfLock->fl_flags & FL_LEASE)
532 533 534
		cFYI(1, ("Lease on file - not implemented yet"));
	if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
		cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
535 536

	if (pfLock->fl_type == F_WRLCK) {
537
		cFYI(1, ("F_WRLCK "));
538 539
		numLock = 1;
	} else if (pfLock->fl_type == F_UNLCK) {
540
		cFYI(1, ("F_UNLCK "));
541 542
		numUnlock = 1;
	} else if (pfLock->fl_type == F_RDLCK) {
543
		cFYI(1, ("F_RDLCK "));
544 545 546
		lockType |= LOCKING_ANDX_SHARED_LOCK;
		numLock = 1;
	} else if (pfLock->fl_type == F_EXLCK) {
547
		cFYI(1, ("F_EXLCK "));
548 549
		numLock = 1;
	} else if (pfLock->fl_type == F_SHLCK) {
550
		cFYI(1, ("F_SHLCK "));
551 552 553
		lockType |= LOCKING_ANDX_SHARED_LOCK;
		numLock = 1;
	} else
554
		cFYI(1, ("Unknown type of lock "));
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;

	if (file->private_data == NULL) {
		FreeXid(xid);
		return -EBADF;
	}

	if (IS_GETLK(cmd)) {
		rc = CIFSSMBLock(xid, pTcon,
				 ((struct cifsFileInfo *) file->
				  private_data)->netfid,
				 length,
				 pfLock->fl_start, 0, 1, lockType,
				 0 /* wait flag */ );
		if (rc == 0) {
			rc = CIFSSMBLock(xid, pTcon,
					 ((struct cifsFileInfo *) file->
					  private_data)->netfid,
					 length,
					 pfLock->fl_start, 1 /* numUnlock */ ,
					 0 /* numLock */ , lockType,
					 0 /* wait flag */ );
			pfLock->fl_type = F_UNLCK;
			if (rc != 0)
				cERROR(1,
582
					("Error unlocking previously locked range %d during test of lock ",
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
					rc));
			rc = 0;

		} else {
			/* if rc == ERR_SHARING_VIOLATION ? */
			rc = 0;	/* do not change lock type to unlock since range in use */
		}

		FreeXid(xid);
		return rc;
	}

	rc = CIFSSMBLock(xid, pTcon,
			 ((struct cifsFileInfo *) file->private_data)->
			 netfid, length,
			 pfLock->fl_start, numUnlock, numLock, lockType,
599
			 wait_flag);
600
	if (rc == 0 && (pfLock->fl_flags & FL_POSIX))
601
		posix_lock_file_wait(file, pfLock);
602 603 604 605 606
	FreeXid(xid);
	return rc;
}

ssize_t
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
cifs_user_write(struct file * file, const char __user * write_data,
	   size_t write_size, loff_t * poffset)
{
	int rc = 0;
	unsigned int bytes_written = 0;
	unsigned int total_written;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int xid, long_op;
	struct cifsFileInfo * open_file;

	if(file->f_dentry == NULL)
		return -EBADF;

	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	if(cifs_sb == NULL) {
		return -EBADF;
	}
	pTcon = cifs_sb->tcon;

	/*cFYI(1,
	   (" write %d bytes to offset %lld of %s", write_size,
	   *poffset, file->f_dentry->d_name.name)); */

	if (file->private_data == NULL) {
		return -EBADF;
	} else {
		open_file = (struct cifsFileInfo *) file->private_data;
	}
	
	xid = GetXid();
	if(file->f_dentry->d_inode == NULL) {
		FreeXid(xid);
		return -EBADF;
	}

	if (*poffset > file->f_dentry->d_inode->i_size)
		long_op = 2;  /* writes past end of file can take a long time */
	else
		long_op = 1;

	for (total_written = 0; write_size > total_written;
	     total_written += bytes_written) {
		rc = -EAGAIN;
		while(rc == -EAGAIN) {
			if(file->private_data == NULL) {
				/* file has been closed on us */
				FreeXid(xid);
			/* if we have gotten here we have written some data
			and blocked, and the file has been freed on us
			while we blocked so return what we managed to write */
				return total_written;
			} 
			if(open_file->closePend) {
				FreeXid(xid);
				if(total_written)
					return total_written;
				else
					return -EBADF;
			}
			if (open_file->invalidHandle) {
				if((file->f_dentry == NULL) ||
				   (file->f_dentry->d_inode == NULL)) {
					FreeXid(xid);
					return total_written;
				}
				/* we could deadlock if we called
				 filemap_fdatawait from here so tell
				reopen_file not to flush data to server now */
				rc = cifs_reopen_file(file->f_dentry->d_inode,
					file,FALSE);
				if(rc != 0)
					break;
			}

			rc = CIFSSMBWrite(xid, pTcon,
				  open_file->netfid,
				  write_size - total_written, *poffset,
				  &bytes_written,
				  NULL, write_data + total_written, long_op);
		}
		if (rc || (bytes_written == 0)) {
			if (total_written)
				break;
			else {
				FreeXid(xid);
				return rc;
			}
		} else
			*poffset += bytes_written;
		long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
	}

#ifdef CONFIG_CIFS_STATS
	if(total_written > 0) {
		atomic_inc(&pTcon->num_writes);
		spin_lock(&pTcon->stat_lock);
		pTcon->bytes_written += total_written;
		spin_unlock(&pTcon->stat_lock);
	}
#endif		

	/* since the write may have blocked check these pointers again */
	if(file->f_dentry) {
		if(file->f_dentry->d_inode) {
			file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
				CURRENT_TIME;
			if (total_written > 0) {
				if (*poffset > file->f_dentry->d_inode->i_size)
					i_size_write(file->f_dentry->d_inode, *poffset);
			}
			mark_inode_dirty_sync(file->f_dentry->d_inode);
		}
	}
	FreeXid(xid);
	return total_written;
}

static ssize_t
726 727 728 729
cifs_write(struct file * file, const char *write_data,
	   size_t write_size, loff_t * poffset)
{
	int rc = 0;
730 731
	unsigned int bytes_written = 0;
	unsigned int total_written;
732 733 734
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int xid, long_op;
735
	struct cifsFileInfo * open_file;
736

737 738 739
	if(file->f_dentry == NULL)
		return -EBADF;

740
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
741 742 743
	if(cifs_sb == NULL) {
		return -EBADF;
	}
744 745 746
	pTcon = cifs_sb->tcon;

	/*cFYI(1,
747
	   (" write %d bytes to offset %lld of %s", write_size,
748 749 750 751
	   *poffset, file->f_dentry->d_name.name)); */

	if (file->private_data == NULL) {
		return -EBADF;
752 753
	} else {
		open_file = (struct cifsFileInfo *) file->private_data;
754
	}
755 756
	
	xid = GetXid();
757 758 759 760
	if(file->f_dentry->d_inode == NULL) {
		FreeXid(xid);
		return -EBADF;
	}
761 762

	if (*poffset > file->f_dentry->d_inode->i_size)
763
		long_op = 2;  /* writes past end of file can take a long time */
764 765 766 767 768
	else
		long_op = 1;

	for (total_written = 0; write_size > total_written;
	     total_written += bytes_written) {
769 770
		rc = -EAGAIN;
		while(rc == -EAGAIN) {
771 772 773
			if(file->private_data == NULL) {
				/* file has been closed on us */
				FreeXid(xid);
774 775 776
			/* if we have gotten here we have written some data
			and blocked, and the file has been freed on us
			while we blocked so return what we managed to write */
777
				return total_written;
778 779 780 781 782 783 784
			} 
			if(open_file->closePend) {
				FreeXid(xid);
				if(total_written)
					return total_written;
				else
					return -EBADF;
785
			}
786 787 788
			if (open_file->invalidHandle) {
				if((file->f_dentry == NULL) ||
				   (file->f_dentry->d_inode == NULL)) {
789 790 791
					FreeXid(xid);
					return total_written;
				}
792 793 794 795 796
				/* we could deadlock if we called
				 filemap_fdatawait from here so tell
				reopen_file not to flush data to server now */
				rc = cifs_reopen_file(file->f_dentry->d_inode,
					file,FALSE);
797 798 799 800 801
				if(rc != 0)
					break;
			}

			rc = CIFSSMBWrite(xid, pTcon,
802
				  open_file->netfid,
803 804
				  write_size - total_written, *poffset,
				  &bytes_written,
805
				  write_data + total_written, NULL, long_op);
806
		}
807 808 809 810 811 812 813 814 815 816 817
		if (rc || (bytes_written == 0)) {
			if (total_written)
				break;
			else {
				FreeXid(xid);
				return rc;
			}
		} else
			*poffset += bytes_written;
		long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
	}
818

819 820 821 822 823 824 825 826 827
#ifdef CONFIG_CIFS_STATS
	if(total_written > 0) {
		atomic_inc(&pTcon->num_writes);
		spin_lock(&pTcon->stat_lock);
		pTcon->bytes_written += total_written;
		spin_unlock(&pTcon->stat_lock);
	}
#endif		

828 829 830 831 832
	/* since the write may have blocked check these pointers again */
	if(file->f_dentry) {
		if(file->f_dentry->d_inode) {
			file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
				CURRENT_TIME;
833
			if (total_written > 0) {
834 835 836 837 838
				if (*poffset > file->f_dentry->d_inode->i_size)
					i_size_write(file->f_dentry->d_inode, *poffset);
			}
			mark_inode_dirty_sync(file->f_dentry->d_inode);
		}
839
	}
840
	FreeXid(xid);
841 842 843 844
	return total_written;
}

static int
845
cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
846 847
{
	struct address_space *mapping = page->mapping;
848
	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
849
	char * write_data;
850 851 852 853
	int rc = -EFAULT;
	int bytes_written = 0;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
854
	struct inode *inode;
855 856
	struct cifsInodeInfo *cifsInode;
	struct cifsFileInfo *open_file = NULL;
857
	struct list_head *tmp;
858
	struct list_head *tmp1;
859 860 861

	if (!mapping) {
		return -EFAULT;
862 863
	} else if(!mapping->host) {
		return -EFAULT;
864 865
	}

866 867 868 869
	inode = page->mapping->host;
	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;

870
	offset += (loff_t)from;
871
	write_data = kmap(page);
872 873
	write_data += from;

874
	if((to > PAGE_CACHE_SIZE) || (from > to)) {
875
		kunmap(page);
876
		return -EIO;
877
	}
878

879 880 881 882 883 884
	/* racing with truncate? */
	if(offset > mapping->host->i_size) {
		kunmap(page);
		return 0; /* don't care */
	}

885
	/* check to make sure that we are not extending the file */
886
	if(mapping->host->i_size - offset < (loff_t)to)
887 888
		to = (unsigned)(mapping->host->i_size - offset); 
		
889 890

	cifsInode = CIFS_I(mapping->host);
891
	read_lock(&GlobalSMBSeslock); 
Steve French's avatar
Steve French committed
892
	/* BB we should start at the end */
893
	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
894
		open_file = list_entry(tmp,struct cifsFileInfo, flist);
895 896
		if(open_file->closePend)
			continue;
897
		/* We check if file is open for writing first */
898 899 900
		if((open_file->pfile) && 
		   ((open_file->pfile->f_flags & O_RDWR) || 
			(open_file->pfile->f_flags & O_WRONLY))) {
901
			read_unlock(&GlobalSMBSeslock);
902
			bytes_written = cifs_write(open_file->pfile, write_data,
903
					to-from, &offset);
904
			read_lock(&GlobalSMBSeslock);
905
		/* Does mm or vfs already set times? */
906 907 908 909
			inode->i_atime = inode->i_mtime = CURRENT_TIME;
			if ((bytes_written > 0) && (offset)) {
				rc = 0;
			} else if(bytes_written < 0) {
910 911 912 913 914 915 916 917 918
				if(rc == -EBADF) {
				/* have seen a case in which
				kernel seemed to have closed/freed a file
				even with writes active so we might as well
				see if there are other file structs to try
				for the same inode before giving up */
					continue;
				} else
					rc = bytes_written;
919
			}
920 921 922
			break;  /* now that we found a valid file handle
				and tried to write to it we are done, no
				sense continuing to loop looking for another */
923
		}
924 925 926 927
		if(tmp->next == NULL) {
			cFYI(1,("File instance %p removed",tmp));
			break;
		}
928
	}
929
	read_unlock(&GlobalSMBSeslock);
930 931
	if(open_file == NULL) {
		cFYI(1,("No writeable filehandles for inode"));
932
		rc = -EIO;
933 934
	}

935
	kunmap(page);
936 937 938
	return rc;
}

939
#if 0
940 941 942 943 944 945 946 947 948 949 950
static int
cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
	int rc = -EFAULT;
	int xid;

	xid = GetXid();
/* call 16K write then Setpageuptodate */
	FreeXid(xid);
	return rc;
}
951
#endif
952

953
static int
Andrew Morton's avatar
Andrew Morton committed
954
cifs_writepage(struct page* page, struct writeback_control *wbc)
955
{
956 957 958 959
	int rc = -EFAULT;
	int xid;

	xid = GetXid();
960
/* BB add check for wbc flags */
961
	page_cache_get(page);
962 963 964
        if (!PageUptodate(page)) {
		cFYI(1,("ppw - page not up to date"));
	}
965
	
966
	rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
967
	SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
968 969 970 971
	unlock_page(page);
	page_cache_release(page);	
	FreeXid(xid);
	return rc;
972 973 974 975 976 977
}

static int
cifs_commit_write(struct file *file, struct page *page, unsigned offset,
		  unsigned to)
{
978 979 980 981
	int xid;
	int rc = 0;
	struct inode *inode = page->mapping->host;
	loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
982
	char * page_data;
983

984
	xid = GetXid();
Steve French's avatar
Steve French committed
985
	cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
986
	if (position > inode->i_size){
987
		i_size_write(inode, position);
988
		/*if (file->private_data == NULL) {
989 990 991
			rc = -EBADF;
		} else {
			open_file = (struct cifsFileInfo *)file->private_data;
992 993 994
			cifs_sb = CIFS_SB(inode->i_sb);
			rc = -EAGAIN;
			while(rc == -EAGAIN) {
995 996 997 998 999
				if((open_file->invalidHandle) && 
				  (!open_file->closePend)) {
					rc = cifs_reopen_file(file->f_dentry->d_inode,file);
					if(rc != 0)
						break;
1000
				}
1001 1002 1003 1004 1005 1006 1007 1008
				if(!open_file->closePend) {
					rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, 
						position, open_file->netfid,
						open_file->pid,FALSE);
				} else {
					rc = -EBADF;
					break;
				}
1009
			}
1010
			cFYI(1,(" SetEOF (commit write) rc = %d",rc));
1011
		}*/
1012
	}
1013
	if (!PageUptodate(page)) {
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
		position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
		/* can not rely on (or let) writepage write this data */
		if(to < offset) {
			cFYI(1,("Illegal offsets, can not copy from %d to %d",
				offset,to));
			FreeXid(xid);
			return rc;
		}
		/* this is probably better than directly calling 
		partialpage_write since in this function
		the file handle is known which we might as well
		leverage */
		/* BB check if anything else missing out of ppw */
		/* such as updating last write time */
		page_data = kmap(page);
		rc = cifs_write(file, page_data+offset,to-offset,
                                        &position);
		if(rc > 0)
			rc = 0;
		/* else if rc < 0 should we set writebehind rc? */
		kunmap(page);
	} else {	
		set_page_dirty(page);
	}
1038

1039
	FreeXid(xid);
1040 1041 1042 1043 1044 1045 1046 1047
	return rc;
}

int
cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	int xid;
	int rc = 0;
1048 1049
	struct inode * inode = file->f_dentry->d_inode;

1050
	xid = GetXid();
1051 1052 1053 1054 1055

	cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
		dentry->d_name.name, datasync));
	
	rc = filemap_fdatawrite(inode->i_mapping);
1056 1057
	if(rc == 0)
		CIFS_I(inode)->write_behind_rc = 0;
1058 1059 1060 1061
	FreeXid(xid);
	return rc;
}

1062
/* static int
1063 1064 1065 1066 1067 1068 1069 1070
cifs_sync_page(struct page *page)
{
	struct address_space *mapping;
	struct inode *inode;
	unsigned long index = page->index;
	unsigned int rpages = 0;
	int rc = 0;

1071
	cFYI(1,("sync page %p",page));
1072 1073 1074 1075 1076
	mapping = page->mapping;
	if (!mapping)
		return 0;
	inode = mapping->host;
	if (!inode)
1077
		return 0;*/
1078 1079 1080 1081

/*	fill in rpages then 
    result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */

1082
/*   cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
1083 1084 1085 1086

	if (rc < 0)
		return rc;
	return 0;
1087
} */
1088

1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
/*
 * As file closes, flush all cached write data for this inode checking
 * for write behind errors.
 *
 */
int cifs_flush(struct file *file)
{
	struct inode * inode = file->f_dentry->d_inode;
	int rc = 0;

	/* Rather than do the steps manually: */
	/* lock the inode for writing */
	/* loop through pages looking for write behind data (dirty pages) */
	/* coalesce into contiguous 16K (or smaller) chunks to write to server */
	/* send to server (prefer in parallel) */
	/* deal with writebehind errors */
	/* unlock inode for writing */
	/* filemapfdatawrite appears easier for the time being */

	rc = filemap_fdatawrite(inode->i_mapping);
1109 1110 1111
	if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
		CIFS_I(inode)->write_behind_rc = 0;
		
1112 1113 1114 1115 1116 1117
	cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));

	return rc;
}


1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
ssize_t
cifs_user_read(struct file * file, char __user *read_data, size_t read_size,
	  loff_t * poffset)
{
	int rc = -EACCES;
	unsigned int bytes_read = 0;
	unsigned int total_read = 0;
	unsigned int current_read_size;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int xid;
	struct cifsFileInfo * open_file;
	char * smb_read_data;
Steve French's avatar
Steve French committed
1131
	char __user * current_offset;
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	struct smb_com_read_rsp * pSMBr;

	xid = GetXid();
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;

	if (file->private_data == NULL) {
		FreeXid(xid);
		return -EBADF;
	}
	open_file = (struct cifsFileInfo *)file->private_data;

	if((file->f_flags & O_ACCMODE) == O_WRONLY) {
		cFYI(1,("attempting read on write only file instance"));
	}

	for (total_read = 0,current_offset=read_data; read_size > total_read;
				total_read += bytes_read,current_offset+=bytes_read) {
		current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
		rc = -EAGAIN;
		smb_read_data = NULL;
		while(rc == -EAGAIN) {
			if ((open_file->invalidHandle) && (!open_file->closePend)) {
				rc = cifs_reopen_file(file->f_dentry->d_inode,
					file,TRUE);
				if(rc != 0)
					break;
			}

			rc = CIFSSMBRead(xid, pTcon,
				 open_file->netfid,
				 current_read_size, *poffset,
				 &bytes_read, &smb_read_data);

			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Steve French's avatar
Steve French committed
1167 1168
			copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/
				+ le16_to_cpu(pSMBr->DataOffset), bytes_read);
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
			if(smb_read_data) {
				cifs_buf_release(smb_read_data);
				smb_read_data = NULL;
			}
		}
		if (rc || (bytes_read == 0)) {
			if (total_read) {
				break;
			} else {
				FreeXid(xid);
				return rc;
			}
		} else {
#ifdef CONFIG_CIFS_STATS
			atomic_inc(&pTcon->num_reads);
			spin_lock(&pTcon->stat_lock);
			pTcon->bytes_read += total_read;
			spin_unlock(&pTcon->stat_lock);
#endif
			*poffset += bytes_read;
		}
	}
	FreeXid(xid);
	return total_read;
}

1195
static ssize_t
1196 1197 1198 1199
cifs_read(struct file * file, char *read_data, size_t read_size,
	  loff_t * poffset)
{
	int rc = -EACCES;
1200 1201 1202
	unsigned int bytes_read = 0;
	unsigned int total_read;
	unsigned int current_read_size;
1203 1204 1205
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int xid;
1206
	char * current_offset;
1207
	struct cifsFileInfo * open_file;
1208 1209 1210 1211 1212 1213 1214 1215 1216

	xid = GetXid();
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;

	if (file->private_data == NULL) {
		FreeXid(xid);
		return -EBADF;
	}
1217
	open_file = (struct cifsFileInfo *)file->private_data;
1218

1219 1220 1221 1222
	if((file->f_flags & O_ACCMODE) == O_WRONLY) {
		cFYI(1,("attempting read on write only file instance"));
	}

1223 1224
	for (total_read = 0,current_offset=read_data; read_size > total_read;
				total_read += bytes_read,current_offset+=bytes_read) {
1225
		current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
1226 1227 1228
		rc = -EAGAIN;
		while(rc == -EAGAIN) {
			if ((open_file->invalidHandle) && (!open_file->closePend)) {
1229 1230
				rc = cifs_reopen_file(file->f_dentry->d_inode,
					file,TRUE);
1231 1232 1233 1234 1235 1236
				if(rc != 0)
					break;
			}

			rc = CIFSSMBRead(xid, pTcon,
				 open_file->netfid,
1237
				 current_read_size, *poffset,
1238
				 &bytes_read, &current_offset);
1239 1240 1241 1242 1243 1244 1245 1246 1247
		}
		if (rc || (bytes_read == 0)) {
			if (total_read) {
				break;
			} else {
				FreeXid(xid);
				return rc;
			}
		} else {
1248 1249 1250 1251 1252 1253
#ifdef CONFIG_CIFS_STATS
			atomic_inc(&pTcon->num_reads);
			spin_lock(&pTcon->stat_lock);
			pTcon->bytes_read += total_read;
			spin_unlock(&pTcon->stat_lock);
#endif
1254
			*poffset += bytes_read;
1255
		}
1256 1257 1258 1259 1260
	}
	FreeXid(xid);
	return total_read;
}

1261
int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
1262 1263 1264 1265
{
	struct dentry * dentry = file->f_dentry;
	int	rc, xid;

1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
#ifdef CIFS_EXPERIMENTAL   /* BB fixme reenable when cifs_read_wrapper fixed */
	if(dentry->d_sb) {
		struct cifs_sb_info *cifs_sb;
		cifs_sb = CIFS_SB(sb);
		if(cifs_sb != NULL) {
			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
				return -ENODEV
		}
	}
#endif /* CIFS_EXPERIMENTAL */

1277 1278 1279
	xid = GetXid();
	rc = cifs_revalidate(dentry);
	if (rc) {
1280
		cFYI(1,("Validation prior to mmap failed, error=%d", rc));
1281 1282 1283 1284 1285 1286 1287 1288
		FreeXid(xid);
		return rc;
	}
	rc = generic_file_mmap(file, vma);
	FreeXid(xid);
	return rc;
}

1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
static void cifs_copy_cache_pages(struct address_space *mapping, 
		struct list_head *pages, int bytes_read, 
		char *data,struct pagevec * plru_pvec)
{
	struct page *page;
	char * target;

	while (bytes_read > 0) {
		if(list_empty(pages))
			break;
1299

1300 1301
		page = list_entry(pages->prev, struct page, lru);
		list_del(&page->lru);
1302

1303 1304
		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
			page_cache_release(page);
1305
			cFYI(1,("Add page cache failed"));
1306 1307 1308
			continue;
		}

1309
		target = kmap_atomic(page,KM_USER0);
1310 1311 1312

		if(PAGE_CACHE_SIZE > bytes_read) {
			memcpy(target,data,bytes_read);
1313 1314
			/* zero the tail end of this partial page */
			memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
1315 1316 1317 1318 1319
			bytes_read = 0;
		} else {
			memcpy(target,data,PAGE_CACHE_SIZE);
			bytes_read -= PAGE_CACHE_SIZE;
		}
1320
		kunmap_atomic(target,KM_USER0);
1321 1322 1323

		flush_dcache_page(page);
		SetPageUptodate(page);
1324 1325 1326
		unlock_page(page);
		if (!pagevec_add(plru_pvec, page))
			__pagevec_lru_add(plru_pvec);
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
		data += PAGE_CACHE_SIZE;
	}
	return;
}


static int
cifs_readpages(struct file *file, struct address_space *mapping,
		struct list_head *page_list, unsigned num_pages)
{
	int rc = -EACCES;
1338
	int xid;
1339 1340 1341 1342 1343
	loff_t offset;
	struct page * page;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int bytes_read = 0;
1344
	unsigned int read_size,i;
1345
	char * smb_read_data = NULL;
1346 1347
	struct smb_com_read_rsp * pSMBr;
	struct pagevec lru_pvec;
1348
	struct cifsFileInfo * open_file;
1349 1350 1351 1352 1353 1354

	xid = GetXid();
	if (file->private_data == NULL) {
		FreeXid(xid);
		return -EBADF;
	}
1355
	open_file = (struct cifsFileInfo *)file->private_data;
1356 1357 1358 1359 1360 1361
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;

	pagevec_init(&lru_pvec, 0);

	for(i = 0;i<num_pages;) {
Steve French's avatar
Steve French committed
1362
		unsigned contig_pages;
1363 1364 1365
		struct page * tmp_page;
		unsigned long expected_index;

1366 1367 1368
		if(list_empty(page_list)) {
			break;
		}
1369
		page = list_entry(page_list->prev, struct page, lru);
1370
		offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1371 1372 1373

		/* count adjacent pages that we will read into */
		contig_pages = 0;
1374 1375
		expected_index = list_entry(page_list->prev,struct page,lru)->index;
		list_for_each_entry_reverse(tmp_page,page_list,lru) {
1376 1377 1378 1379 1380 1381 1382
			if(tmp_page->index == expected_index) {
				contig_pages++;
				expected_index++;
			} else {
				break; 
			}
		}
Steve French's avatar
Steve French committed
1383
		if(contig_pages + i >  num_pages) {
1384 1385
			contig_pages = num_pages - i;
		}
1386

1387 1388
		/* for reads over a certain size could initiate async read ahead */

1389
		read_size = contig_pages * PAGE_CACHE_SIZE;
1390 1391
		/* Read size needs to be in multiples of one page */
		read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
1392

1393 1394 1395
		rc = -EAGAIN;
		while(rc == -EAGAIN) {
			if ((open_file->invalidHandle) && (!open_file->closePend)) {
1396 1397
				rc = cifs_reopen_file(file->f_dentry->d_inode,
					file, TRUE);
1398 1399 1400 1401 1402 1403 1404 1405
				if(rc != 0)
					break;
			}

			rc = CIFSSMBRead(xid, pTcon,
				open_file->netfid,
				read_size, offset,
				&bytes_read, &smb_read_data);
1406
			/* BB need to check return code here */
1407 1408 1409
			if(rc== -EAGAIN) {
				if(smb_read_data) {
					cifs_buf_release(smb_read_data);
1410
					smb_read_data = NULL;
1411 1412
				}
			}
1413
		}
1414 1415 1416 1417
		if ((rc < 0) || (smb_read_data == NULL)) {
			cFYI(1,("Read error in readpages: %d",rc));
			/* clean up remaing pages off list */
			while (!list_empty(page_list) && (i < num_pages)) {
1418
				page = list_entry(page_list->prev, struct page, lru);
1419
				list_del(&page->lru);
1420
				page_cache_release(page);
1421 1422
			}
			break;
1423
		} else if (bytes_read > 0) {
1424 1425
			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
			cifs_copy_cache_pages(mapping, page_list, bytes_read,
1426
				smb_read_data + 4 /* RFC1001 hdr */ +
1427
				le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1428

1429
			i +=  bytes_read >> PAGE_CACHE_SHIFT;
1430 1431 1432 1433 1434 1435
#ifdef CONFIG_CIFS_STATS
			atomic_inc(&pTcon->num_reads);
			spin_lock(&pTcon->stat_lock);
			pTcon->bytes_read += bytes_read;
			spin_unlock(&pTcon->stat_lock);
#endif
Steve French's avatar
Steve French committed
1436
			if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
				i++; /* account for partial page */

				/* server copy of file can have smaller size than client */
				/* BB do we need to verify this common case ? this case is ok - 
				if we are at server EOF we will hit it on next read */

			/* while(!list_empty(page_list) && (i < num_pages)) {
					page = list_entry(page_list->prev,struct page, list);
					list_del(&page->list);
					page_cache_release(page);
				}
				break; */
1449 1450
			}
		} else {
Steve French's avatar
Steve French committed
1451
			cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); 
1452 1453
			/* BB turn off caching and do new lookup on file size at server? */
			while (!list_empty(page_list) && (i < num_pages)) {
1454
				page = list_entry(page_list->prev, struct page, lru);
1455
				list_del(&page->lru);
1456
				page_cache_release(page); /* BB removeme - replace with zero of page? */
1457
			}
1458 1459 1460
			break;
		}
		if(smb_read_data) {
1461
			cifs_buf_release(smb_read_data);
1462
			smb_read_data = NULL;
1463 1464
		}
		bytes_read = 0;
1465 1466 1467 1468
	}

	pagevec_lru_add(&lru_pvec);

1469
/* need to free smb_read_data buf before exit */
1470 1471
	if(smb_read_data) {
		cifs_buf_release(smb_read_data);
1472
		smb_read_data = NULL;
1473
	} 
1474

1475 1476 1477 1478
	FreeXid(xid);
	return rc;
}

1479 1480 1481 1482 1483
static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
{
	char * read_data;
	int rc;

Steve French's avatar
Steve French committed
1484 1485 1486
	page_cache_get(page);
	read_data = kmap(page);
	/* for reads over a certain size could initiate async read ahead */
1487
                                                                                                                           
Steve French's avatar
Steve French committed
1488
	rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1489
                                                                                                                           
Steve French's avatar
Steve French committed
1490 1491 1492 1493 1494
	if (rc < 0)
		goto io_error;
	else {
		cFYI(1,("Bytes read %d ",rc));
	}
1495
                                                                                                                           
Steve French's avatar
Steve French committed
1496
	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
1497
                                                                                                                           
Steve French's avatar
Steve French committed
1498 1499 1500 1501 1502 1503
	if(PAGE_CACHE_SIZE > rc) {
		memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
	}
	flush_dcache_page(page);
	SetPageUptodate(page);
	rc = 0;
1504 1505 1506 1507 1508 1509 1510
                                                                                                                           
io_error:
        kunmap(page);
	page_cache_release(page);
	return rc;
}

1511
static int
1512
cifs_readpage(struct file *file, struct page *page)
1513
{
1514
	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1515 1516 1517 1518 1519 1520 1521 1522 1523
	int rc = -EACCES;
	int xid;

	xid = GetXid();

	if (file->private_data == NULL) {
		FreeXid(xid);
		return -EBADF;
	}
1524

1525
	cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
1526

1527
	rc = cifs_readpage_worker(file,page,&offset);
1528 1529

	unlock_page(page);
1530

1531
	FreeXid(xid);
1532 1533 1534
	return rc;
}

1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
/* We do not want to update the file size from server for inodes
   open for write - to avoid races with writepage extending
   the file - in the future we could consider allowing
   refreshing the inode only on increases in the file size 
   but this is tricky to do without racing with writebehind
   page caching in the current Linux kernel design */
   
int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
{
	struct list_head *tmp;
	struct list_head *tmp1;
	struct cifsFileInfo *open_file = NULL;
	int rc = TRUE;

	if(cifsInode == NULL)
		return rc;

	read_lock(&GlobalSMBSeslock); 
	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
		open_file = list_entry(tmp,struct cifsFileInfo, flist);
		if(open_file == NULL)
			break;
		if(open_file->closePend)
			continue;
	/* We check if file is open for writing,   
	BB we could supplement this with a check to see if file size
	changes have been flushed to server - ie inode metadata dirty */
		if((open_file->pfile) && 
	   ((open_file->pfile->f_flags & O_RDWR) || 
		(open_file->pfile->f_flags & O_WRONLY))) {
			 rc = FALSE;
			 break;
		}
		if(tmp->next == NULL) {
			cFYI(1,("File instance %p removed",tmp));
			break;
		}
	}
	read_unlock(&GlobalSMBSeslock);
	return rc;
}


1578 1579 1580 1581 1582
void
fill_in_inode(struct inode *tmp_inode,
	      FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
{
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1583
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1584 1585 1586
	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
	__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
1587

1588
	cifsInfo->cifsAttrs = attr;
1589 1590
	cifsInfo->time = jiffies;

1591
	/* Linux can not store file creation time unfortunately so ignore it */
1592
	tmp_inode->i_atime =
1593
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1594
	tmp_inode->i_mtime =
1595
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
1596
	tmp_inode->i_ctime =
1597
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
1598 1599
	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
	/* 2767 perms - indicate mandatory locking */
1600 1601
		/* BB fill in uid and gid here? with help from winbind? 
			or retrieve from NTFS stream extended attribute */
1602 1603 1604 1605 1606 1607
	if(atomic_read(&cifsInfo->inUse) == 0) {
		tmp_inode->i_uid = cifs_sb->mnt_uid;
		tmp_inode->i_gid = cifs_sb->mnt_gid;
		/* set default mode. will override for dirs below */
		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
	}
1608

1609
	cFYI(0,
1610
	     ("CIFS FFIRST: Attributes came in as 0x%x",
1611
	      attr));
1612
	if (attr & ATTR_DIRECTORY) {
1613
		*pobject_type = DT_DIR;
1614
		/* override default perms since we do not lock dirs */
1615 1616 1617
		if(atomic_read(&cifsInfo->inUse) == 0) {
			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
		}
1618
		tmp_inode->i_mode |= S_IFDIR;
1619 1620 1621 1622
/* we no longer mark these because we could not follow them */
/*        } else if (attr & ATTR_REPARSE) {
                *pobject_type = DT_LNK;
                tmp_inode->i_mode |= S_IFLNK;*/
1623 1624 1625
	} else {
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
1626
		if(attr & ATTR_READONLY)
1627
			tmp_inode->i_mode &= ~(S_IWUGO);
1628 1629
	}/* could add code here - to validate if device or weird share type? */

1630
	/* can not fill in nlink here as in qpathinfo version and Unx search */
1631 1632 1633 1634
	if(atomic_read(&cifsInfo->inUse) == 0) {
		atomic_set(&cifsInfo->inUse,1);
	}

1635 1636 1637
	if(is_size_safe_to_change(cifsInfo)) {
		/* can not safely change the file size here if the 
		client is writing to it due to potential races */
1638
		i_size_write(tmp_inode,end_of_file);
1639 1640 1641

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, even though the reported blocksize is larger */
1642
		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
1643
	}
1644

1645
	if (allocation_size < end_of_file)
1646
		cFYI(1, ("Possible sparse file: allocation size less than end of file "));
1647
	cFYI(1,
1648
	     ("File Size %ld and blocks %ld and blocksize %ld",
1649 1650 1651 1652 1653 1654
	      (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
	      tmp_inode->i_blksize));
	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, (" File inode "));
		tmp_inode->i_op = &cifs_file_inode_ops;
		tmp_inode->i_fop = &cifs_file_ops;
1655
		tmp_inode->i_data.a_ops = &cifs_addr_ops;
1656 1657 1658 1659 1660 1661 1662 1663
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, (" Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, (" Symbolic Link inode "));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
	} else {
1664
		cFYI(1, (" Init special inode "));
1665
		init_special_inode(tmp_inode, tmp_inode->i_mode,
1666
				   tmp_inode->i_rdev);
1667 1668 1669 1670 1671 1672 1673 1674
	}
}

void
unix_fill_in_inode(struct inode *tmp_inode,
		   FILE_UNIX_INFO * pfindData, int *pobject_type)
{
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1675 1676 1677
	__u32 type = le32_to_cpu(pfindData->Type);
	__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
1678 1679 1680 1681
	cifsInfo->time = jiffies;
	atomic_inc(&cifsInfo->inUse);

	tmp_inode->i_atime =
1682
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1683
	tmp_inode->i_mtime =
1684
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
1685
	tmp_inode->i_ctime =
1686
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
1687 1688

	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
1689
	if (type == UNIX_FILE) {
1690 1691
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
1692
	} else if (type == UNIX_SYMLINK) {
1693 1694
		*pobject_type = DT_LNK;
		tmp_inode->i_mode |= S_IFLNK;
1695
	} else if (type == UNIX_DIR) {
1696 1697
		*pobject_type = DT_DIR;
		tmp_inode->i_mode |= S_IFDIR;
1698
	} else if (type == UNIX_CHARDEV) {
1699 1700
		*pobject_type = DT_CHR;
		tmp_inode->i_mode |= S_IFCHR;
1701 1702
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1703
	} else if (type == UNIX_BLOCKDEV) {
1704 1705
		*pobject_type = DT_BLK;
		tmp_inode->i_mode |= S_IFBLK;
1706 1707
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
1708
	} else if (type == UNIX_FIFO) {
1709 1710
		*pobject_type = DT_FIFO;
		tmp_inode->i_mode |= S_IFIFO;
1711
	} else if (type == UNIX_SOCKET) {
1712 1713 1714 1715 1716 1717 1718 1719
		*pobject_type = DT_SOCK;
		tmp_inode->i_mode |= S_IFSOCK;
	}

	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
	tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);

1720 1721 1722 1723

	if(is_size_safe_to_change(cifsInfo)) {
		/* can not safely change the file size here if the 
		client is writing to it due to potential races */
1724
		i_size_write(tmp_inode,end_of_file);
1725 1726 1727

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, not the real blocksize */
1728
		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
1729
	}
1730

1731
	if (S_ISREG(tmp_inode->i_mode)) {
1732
		cFYI(1, ("File inode"));
1733 1734
		tmp_inode->i_op = &cifs_file_inode_ops;
		tmp_inode->i_fop = &cifs_file_ops;
1735
		tmp_inode->i_data.a_ops = &cifs_addr_ops;
1736
	} else if (S_ISDIR(tmp_inode->i_mode)) {
1737
		cFYI(1, ("Directory inode"));
1738 1739 1740
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
1741
		cFYI(1, ("Symbolic Link inode"));
1742 1743 1744
		tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
	} else {
1745
		cFYI(1, ("Special inode")); 
1746
		init_special_inode(tmp_inode, tmp_inode->i_mode,
1747
				   tmp_inode->i_rdev);
1748 1749 1750
	}
}

1751 1752
/* Returns one if new inode created (which therefore needs to be hashed) */
/* Might check in the future if inode number changed so we can rehash inode */
1753
int
1754 1755 1756 1757 1758 1759
construct_dentry(struct qstr *qstring, struct file *file,
		 struct inode **ptmp_inode, struct dentry **pnew_dentry)
{
	struct dentry *tmp_dentry;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
1760
	int rc = 0;
1761

1762
	cFYI(1, ("For %s ", qstring->name));
1763 1764 1765 1766 1767 1768
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;

	qstring->hash = full_name_hash(qstring->name, qstring->len);
	tmp_dentry = d_lookup(file->f_dentry, qstring);
	if (tmp_dentry) {
1769
		cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
1770 1771
		*ptmp_inode = tmp_dentry->d_inode;
		/* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
1772 1773
		if(*ptmp_inode == NULL) {
	                *ptmp_inode = new_inode(file->f_dentry->d_sb);
1774
			if(*ptmp_inode == NULL)
1775 1776
				return rc;
			rc = 1;
1777 1778
			d_instantiate(tmp_dentry, *ptmp_inode);
		}
1779 1780
	} else {
		tmp_dentry = d_alloc(file->f_dentry, qstring);
1781 1782
		if(tmp_dentry == NULL) {
			cERROR(1,("Failed allocating dentry"));
1783
			*ptmp_inode = NULL;
1784
			return rc;
1785 1786
		}
			
1787 1788
		*ptmp_inode = new_inode(file->f_dentry->d_sb);
		tmp_dentry->d_op = &cifs_dentry_ops;
1789
		if(*ptmp_inode == NULL)
1790 1791
			return rc;
		rc = 1;
1792 1793 1794 1795 1796 1797
		d_instantiate(tmp_dentry, *ptmp_inode);
		d_rehash(tmp_dentry);
	}

	tmp_dentry->d_time = jiffies;
	*pnew_dentry = tmp_dentry;
1798
	return rc; 
1799 1800
}

1801
static void reset_resume_key(struct file * dir_file, 
1802
				unsigned char * filename, 
1803
				unsigned int len,int Unicode,struct nls_table * nls_tab) {
1804 1805 1806 1807 1808 1809 1810 1811 1812
	struct cifsFileInfo *cifsFile;

	cifsFile = (struct cifsFileInfo *)dir_file->private_data;
	if(cifsFile == NULL)
		return;
	if(cifsFile->search_resume_name) {
		kfree(cifsFile->search_resume_name);
	}

1813 1814
	if(Unicode) 
		len *= 2;
1815
	cifsFile->resume_name_length = len;
1816

1817
	cifsFile->search_resume_name = 
1818 1819
		kmalloc(cifsFile->resume_name_length, GFP_KERNEL);

1820 1821 1822 1823 1824
	if(cifsFile->search_resume_name == NULL) {
		cERROR(1,("failed new resume key allocate, length %d",
				  cifsFile->resume_name_length));
		return;
	}
1825 1826 1827 1828 1829
	if(Unicode)
		cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
			filename, len, nls_tab);
	else
		memcpy(cifsFile->search_resume_name, filename, 
1830
		   cifsFile->resume_name_length);
1831
	cFYI(1,("Reset resume key to: %s with len %d",filename,len));
1832 1833 1834 1835 1836 1837
	return;
}



static int
1838 1839 1840 1841 1842
cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
	     struct file *file, filldir_t filldir, void *direntry)
{
	struct inode *tmp_inode;
	struct dentry *tmp_dentry;
1843
	int object_type,rc;
1844 1845

	pqstring->name = pfindData->FileName;
1846
	/* pqstring->len is already set by caller */
1847

1848
	rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1849 1850 1851
	if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
		return -ENOMEM;
	}
1852
	fill_in_inode(tmp_inode, pfindData, &object_type);
1853 1854 1855 1856 1857 1858 1859 1860
	if(rc) {
		/* We have no reliable way to get inode numbers
		from servers w/o Unix extensions yet so we can not set
		i_ino from pfindData yet */

		/* new inode created, let us hash it */
		insert_inode_hash(tmp_inode);
	} /* else if inode number changed do we rehash it? */
1861
	rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
1862
		tmp_inode->i_ino, object_type);
1863 1864 1865 1866 1867
	if(rc) {
		/* due to readdir error we need to recalculate resume 
		key so next readdir will restart on right entry */
		cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
	}
1868
	dput(tmp_dentry);
1869
	return rc;
1870 1871
}

1872
static int
1873 1874 1875 1876 1877 1878
cifs_filldir_unix(struct qstr *pqstring,
		  FILE_UNIX_INFO * pUnixFindData, struct file *file,
		  filldir_t filldir, void *direntry)
{
	struct inode *tmp_inode;
	struct dentry *tmp_dentry;
1879
	int object_type, rc;
1880 1881 1882 1883

	pqstring->name = pUnixFindData->FileName;
	pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);

1884
	rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1885 1886
	if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
		return -ENOMEM;
1887 1888 1889
	} 
	if(rc) {
		struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1890

1891 1892 1893 1894 1895 1896
		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
			tmp_inode->i_ino = 
				(unsigned long)pUnixFindData->UniqueId;
		}
		insert_inode_hash(tmp_inode);
	} /* else if i_ino has changed should we rehash it? */
1897
	unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
1898
	rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
1899
		file->f_pos, tmp_inode->i_ino, object_type);
1900 1901 1902 1903 1904
	if(rc) {
		/* due to readdir error we need to recalculate resume 
			key so next readdir will restart on right entry */
		cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
	}
1905
	dput(tmp_dentry);
1906
	return rc;
1907 1908 1909 1910 1911 1912
}

int
cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
	int rc = 0;
1913
	int xid;
1914 1915
	int Unicode = FALSE;
	int UnixSearch = FALSE;
1916
	unsigned int bufsize, i;
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
	__u16 searchHandle;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *cifsFile = NULL;
	char *full_path = NULL;
	char *data;
	struct qstr qstring;
	T2_FFIRST_RSP_PARMS findParms;
	T2_FNEXT_RSP_PARMS findNextParms;
	FILE_DIRECTORY_INFO *pfindData;
1927
	FILE_DIRECTORY_INFO *lastFindData;
1928 1929
	FILE_UNIX_INFO *pfindDataUnix;

1930 1931

    /* BB removeme begin */
1932
	if(!experimEnabled)
1933 1934 1935 1936
		return cifs_readdir2(file,direntry,filldir);
    /* BB removeme end */


1937 1938
	xid = GetXid();

1939 1940 1941 1942 1943
	if(file->f_dentry == NULL) {
		rc = -EIO;
		FreeXid(xid);
		return rc;
	}
1944 1945
	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
	pTcon = cifs_sb->tcon;
1946
	bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
1947
	if(bufsize > CIFSMaxBufSize) {
1948
		rc = -EIO;
1949
		FreeXid(xid);
1950
		return rc;
1951 1952
	}
	data = kmalloc(bufsize, GFP_KERNEL);
1953
	pfindData = (FILE_DIRECTORY_INFO *) data;
1954
	if(data == NULL) {
1955
		rc = -ENOMEM;
1956
		FreeXid(xid);
1957
		return rc;
1958 1959
	}
	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
1960
	full_path = build_wildcard_path_from_dentry(file->f_dentry);
1961 1962
	up(&file->f_dentry->d_sb->s_vfs_rename_sem);

1963 1964 1965 1966 1967
	if(full_path == NULL) {
		kfree(data);
		FreeXid(xid);
		return -ENOMEM;
	}
1968
	cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
1969 1970 1971

	switch ((int) file->f_pos) {
	case 0:
1972
		if (filldir(direntry, ".", 1, file->f_pos,
1973
		     file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
1974
			cERROR(1, ("Filldir for current dir failed "));
1975 1976 1977 1978 1979
			break;
		}
		file->f_pos++;
		/* fallthrough */
	case 1:
1980
		if (filldir(direntry, "..", 2, file->f_pos,
1981
		     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1982
			cERROR(1, ("Filldir for parent dir failed "));
1983 1984 1985 1986 1987
			break;
		}
		file->f_pos++;
		/* fallthrough */
	case 2:
1988
		if (file->private_data != NULL) {
1989 1990
			cifsFile =
				(struct cifsFileInfo *) file->private_data;
1991 1992
			if (cifsFile->srch_inf.endOfSearch) {
				if(cifsFile->srch_inf.emptyDir) {
1993 1994 1995 1996
					cFYI(1, ("End of search, empty dir"));
					rc = 0;
					break;
				}
1997 1998
			} else {
				cifsFile->invalidHandle = TRUE;
1999
				CIFSFindClose(xid, pTcon, cifsFile->netfid);
2000
			}
2001 2002 2003 2004
			if(cifsFile->search_resume_name) {
				kfree(cifsFile->search_resume_name);
				cifsFile->search_resume_name = NULL;
			}
2005
		}
2006 2007 2008
		rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
				&findParms, cifs_sb->local_nls,
				&Unicode, &UnixSearch);
2009 2010 2011
		cFYI(1, ("Count: %d  End: %d ",
			le16_to_cpu(findParms.SearchCount),
			le16_to_cpu(findParms.EndofSearch)));
2012
 
2013
		if (rc == 0) {
2014
			__u16 count = le16_to_cpu(findParms.SearchCount);
2015
			searchHandle = findParms.SearchHandle;
2016 2017
			if(file->private_data == NULL)
				file->private_data =
2018
					kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
2019 2020 2021 2022 2023 2024
			if (file->private_data) {
				memset(file->private_data, 0,
				       sizeof (struct cifsFileInfo));
				cifsFile =
				    (struct cifsFileInfo *) file->private_data;
				cifsFile->netfid = searchHandle;
2025
				cifsFile->invalidHandle = FALSE;
2026
				init_MUTEX(&cifsFile->fh_sem);
2027 2028 2029
			} else {
				rc = -ENOMEM;
				break;
2030 2031 2032
			}

			renew_parental_timestamps(file->f_dentry);
2033 2034
			lastFindData = 
				(FILE_DIRECTORY_INFO *) ((char *) pfindData + 
2035
					le16_to_cpu(findParms.LastNameOffset));
2036 2037 2038 2039 2040 2041
			if((char *)lastFindData > (char *)pfindData + bufsize) {
				cFYI(1,("last search entry past end of packet"));
				rc = -EIO;
				break;
			}
			/* Offset of resume key same for levels 257 and 514 */
2042
			cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
			if(UnixSearch == FALSE) {
				cifsFile->resume_name_length = 
					le32_to_cpu(lastFindData->FileNameLength);
				if(cifsFile->resume_name_length > bufsize - 64) {
					cFYI(1,("Illegal resume file name length %d",
						cifsFile->resume_name_length));
					rc = -ENOMEM;
					break;
				}
				cifsFile->search_resume_name = 
					kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
				cFYI(1,("Last file: %s with name %d bytes long",
					lastFindData->FileName,
					cifsFile->resume_name_length));
2057 2058 2059 2060
				if(cifsFile->search_resume_name == NULL) {
					rc = -ENOMEM;
					break;
				}
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
				memcpy(cifsFile->search_resume_name,
					lastFindData->FileName, 
					cifsFile->resume_name_length);
			} else {
				pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
				if (Unicode == TRUE) {
					for(i=0;(pfindDataUnix->FileName[i] 
						    | pfindDataUnix->FileName[i+1]);
						i+=2) {
						if(i > bufsize-64)
							break;
					}
					cifsFile->resume_name_length = i + 2;
				} else {
					cifsFile->resume_name_length = 
						strnlen(pfindDataUnix->FileName,
							bufsize-63);
				}
				if(cifsFile->resume_name_length > bufsize - 64) {
					cFYI(1,("Illegal resume file name length %d",
						cifsFile->resume_name_length));
					rc = -ENOMEM;
					break;
				}
				cifsFile->search_resume_name = 
					kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
				cFYI(1,("Last file: %s with name %d bytes long",
2088
					pfindDataUnix->FileName,
2089
					cifsFile->resume_name_length));
2090 2091 2092 2093
				if(cifsFile->search_resume_name == NULL) {
					rc = -ENOMEM;
					break;
				}
2094
				memcpy(cifsFile->search_resume_name,
2095
					pfindDataUnix->FileName, 
2096 2097
					cifsFile->resume_name_length);
			}
2098
			for (i = 2; i < count + 2; i++) {
2099
				if (UnixSearch == FALSE) {
2100
					__u32 len = le32_to_cpu(pfindData->FileNameLength);
2101
					if (Unicode == TRUE)
2102
						len =
2103 2104 2105 2106
						    cifs_strfromUCS_le
						    (pfindData->FileName,
						     (wchar_t *)
						     pfindData->FileName,
2107
						     len / 2,
2108
						     cifs_sb->local_nls);
2109 2110
					qstring.len = len;
					if (((len != 1)
2111
					     || (pfindData->FileName[0] != '.'))
2112
					    && ((len != 2)
2113 2114 2115 2116
						|| (pfindData->
						    FileName[0] != '.')
						|| (pfindData->
						    FileName[1] != '.'))) {
2117
						if(cifs_filldir(&qstring,
2118 2119
							     pfindData,
							     file, filldir,
2120 2121 2122 2123
							     direntry)) {
							/* do not end search if
								kernel not ready to take
								remaining entries yet */
2124 2125
							reset_resume_key(file, pfindData->FileName,qstring.len,
								Unicode, cifs_sb->local_nls);
2126 2127 2128
							findParms.EndofSearch = 0;
							break;
						}
2129 2130 2131 2132 2133 2134 2135
						file->f_pos++;
					}
				} else {	/* UnixSearch */
					pfindDataUnix =
					    (FILE_UNIX_INFO *) pfindData;
					if (Unicode == TRUE)
						qstring.len =
2136 2137 2138 2139 2140 2141
							cifs_strfromUCS_le
							(pfindDataUnix->FileName,
							(wchar_t *)
							pfindDataUnix->FileName,
							MAX_PATHCONF,
							cifs_sb->local_nls);
2142 2143
					else
						qstring.len =
2144 2145 2146
							strnlen(pfindDataUnix->
							  FileName,
							  MAX_PATHCONF);
2147 2148 2149 2150 2151 2152 2153 2154
					if (((qstring.len != 1)
					     || (pfindDataUnix->
						 FileName[0] != '.'))
					    && ((qstring.len != 2)
						|| (pfindDataUnix->
						    FileName[0] != '.')
						|| (pfindDataUnix->
						    FileName[1] != '.'))) {
2155
						if(cifs_filldir_unix(&qstring,
2156 2157 2158
								  pfindDataUnix,
								  file,
								  filldir,
2159 2160 2161 2162 2163
								  direntry)) {
							/* do not end search if
								kernel not ready to take
								remaining entries yet */
							findParms.EndofSearch = 0;
2164 2165
							reset_resume_key(file, pfindDataUnix->FileName,
								qstring.len,Unicode,cifs_sb->local_nls);
2166 2167
							break;
						}
2168 2169 2170
						file->f_pos++;
					}
				}
2171 2172 2173 2174
				/* works also for Unix ff struct since first field of both */
				pfindData = 
					(FILE_DIRECTORY_INFO *) ((char *) pfindData
						 + le32_to_cpu(pfindData->NextEntryOffset));
2175
				/* BB also should check to make sure that pointer is not beyond the end of the SMB */
2176
				/* if(pfindData > lastFindData) rc = -EIO; break; */
2177 2178
			}	/* end for loop */
			if ((findParms.EndofSearch != 0) && cifsFile) {
2179
				cifsFile->srch_inf.endOfSearch = TRUE;
2180
				if(findParms.SearchCount == cpu_to_le16(2))
2181
					cifsFile->srch_inf.emptyDir = TRUE;
2182 2183 2184
			}
		} else {
			if (cifsFile)
2185
				cifsFile->srch_inf.endOfSearch = TRUE;
2186 2187
			/* unless parent directory gone do not return error */
			rc = 0;
2188 2189 2190 2191 2192 2193
		}
		break;
	default:
		if (file->private_data == NULL) {
			rc = -EBADF;
			cFYI(1,
2194
			     ("Readdir on closed srch, pos = %lld",
2195 2196 2197
			      file->f_pos));
		} else {
			cifsFile = (struct cifsFileInfo *) file->private_data;
2198
			if (cifsFile->srch_inf.endOfSearch) {
2199
				rc = 0;
2200
				cFYI(1, ("End of search "));
2201 2202 2203 2204
				break;
			}
			searchHandle = cifsFile->netfid;
			rc = CIFSFindNext(xid, pTcon, pfindData,
2205 2206 2207
				&findNextParms, searchHandle, 
				cifsFile->search_resume_name,
				cifsFile->resume_name_length,
2208
				cifsFile->srch_inf.resume_key,
2209 2210
				&Unicode, &UnixSearch);
			cFYI(1,("Count: %d  End: %d ",
2211 2212
			      le16_to_cpu(findNextParms.SearchCount),
			      le16_to_cpu(findNextParms.EndofSearch)));
2213
			if ((rc == 0) && (findNextParms.SearchCount != 0)) {
2214
			/* BB save off resume key, key name and name length  */
2215
				__u16 count = le16_to_cpu(findNextParms.SearchCount);
2216 2217
				lastFindData = 
					(FILE_DIRECTORY_INFO *) ((char *) pfindData 
2218
					+ le16_to_cpu(findNextParms.LastNameOffset));
2219 2220 2221 2222 2223 2224
				if((char *)lastFindData > (char *)pfindData + bufsize) {
					cFYI(1,("last search entry past end of packet"));
					rc = -EIO;
					break;
				}
				/* Offset of resume key same for levels 257 and 514 */
2225
				cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235

				if(UnixSearch == FALSE) {
					cifsFile->resume_name_length = 
						le32_to_cpu(lastFindData->FileNameLength);
					if(cifsFile->resume_name_length > bufsize - 64) {
						cFYI(1,("Illegal resume file name length %d",
							cifsFile->resume_name_length));
						rc = -ENOMEM;
						break;
					}
2236 2237 2238 2239 2240
					/* Free the memory allocated by previous findfirst 
					or findnext call - we can not reuse the memory since
					the resume name may not be same string length */
					if(cifsFile->search_resume_name)
						kfree(cifsFile->search_resume_name);
2241 2242 2243 2244 2245
					cifsFile->search_resume_name = 
						kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
					cFYI(1,("Last file: %s with name %d bytes long",
						lastFindData->FileName,
						cifsFile->resume_name_length));
2246 2247 2248 2249 2250
					if(cifsFile->search_resume_name == NULL) {
						rc = -ENOMEM;
						break;
					}
					
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
					memcpy(cifsFile->search_resume_name,
						lastFindData->FileName, 
						cifsFile->resume_name_length);
				} else {
					pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
					if (Unicode == TRUE) {
						for(i=0;(pfindDataUnix->FileName[i] 
								| pfindDataUnix->FileName[i+1]);
							i+=2) {
							if(i > bufsize-64)
								break;
						}
						cifsFile->resume_name_length = i + 2;
					} else {
						cifsFile->resume_name_length = 
							strnlen(pfindDataUnix->
							 FileName,
							 MAX_PATHCONF);
					}
					if(cifsFile->resume_name_length > bufsize - 64) {
						cFYI(1,("Illegal resume file name length %d",
								cifsFile->resume_name_length));
						rc = -ENOMEM;
						break;
					}
2276 2277 2278 2279 2280
					/* Free the memory allocated by previous findfirst 
					or findnext call - we can not reuse the memory since
					the resume name may not be same string length */
					if(cifsFile->search_resume_name)
						kfree(cifsFile->search_resume_name);
2281 2282 2283
					cifsFile->search_resume_name = 
						kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
					cFYI(1,("fnext last file: %s with name %d bytes long",
2284
						pfindDataUnix->FileName,
2285
						cifsFile->resume_name_length));
2286 2287 2288 2289
					if(cifsFile->search_resume_name == NULL) {
						rc = -ENOMEM;
						break;
					}
2290
					memcpy(cifsFile->search_resume_name,
2291
						pfindDataUnix->FileName, 
2292 2293 2294
						cifsFile->resume_name_length);
				}

2295
				for (i = 0; i < count; i++) {
2296
					__u32 len = le32_to_cpu(pfindData->
2297 2298 2299
							FileNameLength);
					if (UnixSearch == FALSE) {
						if (Unicode == TRUE)
2300
							len =
2301 2302 2303 2304
							  cifs_strfromUCS_le
							  (pfindData->FileName,
							  (wchar_t *)
							  pfindData->FileName,
2305
							  len / 2,
2306
							  cifs_sb->local_nls);
2307 2308
						qstring.len = len;
						if (((len != 1)
2309
						    || (pfindData->FileName[0] != '.'))
2310
						    && ((len != 2)
2311 2312
							|| (pfindData->FileName[0] != '.')
							|| (pfindData->FileName[1] !=
2313
							    '.'))) {
2314
							if(cifs_filldir
2315 2316 2317
							    (&qstring,
							     pfindData,
							     file, filldir,
2318 2319 2320 2321 2322
							     direntry)) {
							/* do not end search if
								kernel not ready to take
								remaining entries yet */
								findNextParms.EndofSearch = 0;
2323 2324
								reset_resume_key(file, pfindData->FileName,qstring.len,
									Unicode,cifs_sb->local_nls);
2325 2326
								break;
							}
2327 2328 2329 2330 2331 2332 2333 2334
							file->f_pos++;
						}
					} else {	/* UnixSearch */
						pfindDataUnix =
						    (FILE_UNIX_INFO *)
						    pfindData;
						if (Unicode == TRUE)
							qstring.len =
2335 2336 2337 2338 2339 2340
							  cifs_strfromUCS_le
							  (pfindDataUnix->FileName,
							  (wchar_t *)
							  pfindDataUnix->FileName,
							  MAX_PATHCONF,
							  cifs_sb->local_nls);
2341 2342
						else
							qstring.len =
2343 2344 2345 2346
							  strnlen
							  (pfindDataUnix->
							  FileName,
							  MAX_PATHCONF);
2347 2348 2349 2350 2351 2352 2353 2354 2355
						if (((qstring.len != 1)
						     || (pfindDataUnix->
							 FileName[0] != '.'))
						    && ((qstring.len != 2)
							|| (pfindDataUnix->
							    FileName[0] != '.')
							|| (pfindDataUnix->
							    FileName[1] !=
							    '.'))) {
2356
							if(cifs_filldir_unix
2357 2358 2359
							    (&qstring,
							     pfindDataUnix,
							     file, filldir,
2360 2361 2362 2363 2364
							     direntry)) {
								/* do not end search if
								kernel not ready to take
								remaining entries yet */
								findNextParms.EndofSearch = 0;
2365 2366
								reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
									Unicode,cifs_sb->local_nls);
2367 2368
								break;
							}
2369 2370 2371
							file->f_pos++;
						}
					}
2372 2373 2374 2375
					pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
						le32_to_cpu(pfindData->NextEntryOffset));
	/* works also for Unix find struct since first field of both */
	/* BB also should check to ensure pointer not beyond end of SMB */
2376
				} /* end for loop */
2377
				if (findNextParms.EndofSearch != 0) {
2378
					cifsFile->srch_inf.endOfSearch = TRUE;
2379 2380
				}
			} else {
2381
				cifsFile->srch_inf.endOfSearch = TRUE;
2382 2383
				rc = 0;	/* unless parent directory disappeared - do not
				return error here (eg Access Denied or no more files) */
2384 2385
			}
		}
2386
	} /* end switch */
2387 2388 2389 2390 2391 2392 2393 2394
	if (data)
		kfree(data);
	if (full_path)
		kfree(full_path);
	FreeXid(xid);

	return rc;
}
2395 2396 2397
int cifs_prepare_write(struct file *file, struct page *page,
			unsigned from, unsigned to)
{
2398 2399
	int rc = 0;
        loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2400
	cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
2401
	if (!PageUptodate(page)) {
2402
	/*	if (to - from != PAGE_CACHE_SIZE) {
2403 2404 2405 2406 2407
			void *kaddr = kmap_atomic(page, KM_USER0);
			memset(kaddr, 0, from);
			memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
			flush_dcache_page(page);
			kunmap_atomic(kaddr, KM_USER0);
2408 2409 2410 2411 2412 2413 2414
		} */
		/* If we are writing a full page it will be up to date,
		no need to read from the server */
		if((to==PAGE_CACHE_SIZE) && (from == 0))
			SetPageUptodate(page);

		/* might as well read a page, it is fast enough */
2415 2416 2417 2418
		if((file->f_flags & O_ACCMODE) != O_WRONLY) {
			rc = cifs_readpage_worker(file,page,&offset);
		} else {
		/* should we try using another
2419 2420
		file handle if there is one - how would we lock it
		to prevent close of that handle racing with this read? */
2421 2422
		/* In any case this will be written out by commit_write */
		}
2423
	}
2424 2425

	/* BB should we pass any errors back? e.g. if we do not have read access to the file */
2426 2427 2428
	return 0;
}

2429 2430 2431

struct address_space_operations cifs_addr_ops = {
	.readpage = cifs_readpage,
2432
	.readpages = cifs_readpages,
2433
	.writepage = cifs_writepage,
2434
	.prepare_write = cifs_prepare_write, 
2435
	.commit_write = cifs_commit_write,
2436
	.set_page_dirty = __set_page_dirty_nobuffers,
2437
   /* .sync_page = cifs_sync_page, */
2438
	/*.direct_IO = */
2439
};