blob: 14a1c72ced92e1cc98024494ea217b2a7413921d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Steve French37c0eb42005-10-05 14:50:29 -070024#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/stat.h>
26#include <linux/fcntl.h>
Steve French37c0eb42005-10-05 14:50:29 -070027#include <linux/mpage.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/pagemap.h>
29#include <linux/pagevec.h>
30#include <linux/smp_lock.h>
Steve French37c0eb42005-10-05 14:50:29 -070031#include <linux/writeback.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/div64.h>
34#include "cifsfs.h"
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41
42static inline struct cifsFileInfo *cifs_init_private(
43 struct cifsFileInfo *private_data, struct inode *inode,
44 struct file *file, __u16 netfid)
45{
46 memset(private_data, 0, sizeof(struct cifsFileInfo));
47 private_data->netfid = netfid;
48 private_data->pid = current->tgid;
49 init_MUTEX(&private_data->fh_sem);
50 private_data->pfile = file; /* needed for writepage */
51 private_data->pInode = inode;
52 private_data->invalidHandle = FALSE;
53 private_data->closePend = FALSE;
Steve French23e7dd72005-10-20 13:44:56 -070054 /* we have to track num writers to the inode, since writepages
55 does not tell us which handle the write is for so there can
56 be a close (overlapping with write) of the filehandle that
57 cifs_writepages chose to use */
58 atomic_set(&private_data->wrtPending,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 return private_data;
61}
62
63static inline int cifs_convert_flags(unsigned int flags)
64{
65 if ((flags & O_ACCMODE) == O_RDONLY)
66 return GENERIC_READ;
67 else if ((flags & O_ACCMODE) == O_WRONLY)
68 return GENERIC_WRITE;
69 else if ((flags & O_ACCMODE) == O_RDWR) {
70 /* GENERIC_ALL is too much permission to request
71 can cause unnecessary access denied on create */
72 /* return GENERIC_ALL; */
73 return (GENERIC_READ | GENERIC_WRITE);
74 }
75
76 return 0x20197;
77}
78
79static inline int cifs_get_disposition(unsigned int flags)
80{
81 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
82 return FILE_CREATE;
83 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
84 return FILE_OVERWRITE_IF;
85 else if ((flags & O_CREAT) == O_CREAT)
86 return FILE_OPEN_IF;
87 else
88 return FILE_OPEN;
89}
90
91/* all arguments to this function must be checked for validity in caller */
92static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
93 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
94 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
95 char *full_path, int xid)
96{
97 struct timespec temp;
98 int rc;
99
100 /* want handles we can use to read with first
101 in the list so we do not have to walk the
102 list to search for one in prepare_write */
103 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
104 list_add_tail(&pCifsFile->flist,
105 &pCifsInode->openFileList);
106 } else {
107 list_add(&pCifsFile->flist,
108 &pCifsInode->openFileList);
109 }
110 write_unlock(&GlobalSMBSeslock);
111 write_unlock(&file->f_owner.lock);
112 if (pCifsInode->clientCanCacheRead) {
113 /* we have the inode open somewhere else
114 no need to discard cache data */
115 goto client_can_cache;
116 }
117
118 /* BB need same check in cifs_create too? */
119 /* if not oplocked, invalidate inode pages if mtime or file
120 size changed */
121 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
122 if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
123 (file->f_dentry->d_inode->i_size ==
124 (loff_t)le64_to_cpu(buf->EndOfFile))) {
125 cFYI(1, ("inode unchanged on server"));
126 } else {
127 if (file->f_dentry->d_inode->i_mapping) {
128 /* BB no need to lock inode until after invalidate
129 since namei code should already have it locked? */
130 filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
131 filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
132 }
133 cFYI(1, ("invalidating remote inode since open detected it "
134 "changed"));
135 invalidate_remote_inode(file->f_dentry->d_inode);
136 }
137
138client_can_cache:
139 if (pTcon->ses->capabilities & CAP_UNIX)
140 rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
141 full_path, inode->i_sb, xid);
142 else
143 rc = cifs_get_inode_info(&file->f_dentry->d_inode,
144 full_path, buf, inode->i_sb, xid);
145
146 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
147 pCifsInode->clientCanCacheAll = TRUE;
148 pCifsInode->clientCanCacheRead = TRUE;
149 cFYI(1, ("Exclusive Oplock granted on inode %p",
150 file->f_dentry->d_inode));
151 } else if ((*oplock & 0xF) == OPLOCK_READ)
152 pCifsInode->clientCanCacheRead = TRUE;
153
154 return rc;
155}
156
157int cifs_open(struct inode *inode, struct file *file)
158{
159 int rc = -EACCES;
160 int xid, oplock;
161 struct cifs_sb_info *cifs_sb;
162 struct cifsTconInfo *pTcon;
163 struct cifsFileInfo *pCifsFile;
164 struct cifsInodeInfo *pCifsInode;
165 struct list_head *tmp;
166 char *full_path = NULL;
167 int desiredAccess;
168 int disposition;
169 __u16 netfid;
170 FILE_ALL_INFO *buf = NULL;
171
172 xid = GetXid();
173
174 cifs_sb = CIFS_SB(inode->i_sb);
175 pTcon = cifs_sb->tcon;
176
177 if (file->f_flags & O_CREAT) {
178 /* search inode for this file and fill in file->private_data */
179 pCifsInode = CIFS_I(file->f_dentry->d_inode);
180 read_lock(&GlobalSMBSeslock);
181 list_for_each(tmp, &pCifsInode->openFileList) {
182 pCifsFile = list_entry(tmp, struct cifsFileInfo,
183 flist);
184 if ((pCifsFile->pfile == NULL) &&
185 (pCifsFile->pid == current->tgid)) {
186 /* mode set in cifs_create */
187
188 /* needed for writepage */
189 pCifsFile->pfile = file;
190
191 file->private_data = pCifsFile;
192 break;
193 }
194 }
195 read_unlock(&GlobalSMBSeslock);
196 if (file->private_data != NULL) {
197 rc = 0;
198 FreeXid(xid);
199 return rc;
200 } else {
201 if (file->f_flags & O_EXCL)
202 cERROR(1, ("could not find file instance for "
203 "new file %p ", file));
204 }
205 }
206
207 down(&inode->i_sb->s_vfs_rename_sem);
Steve French7f573562005-08-30 11:32:14 -0700208 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 up(&inode->i_sb->s_vfs_rename_sem);
210 if (full_path == NULL) {
211 FreeXid(xid);
212 return -ENOMEM;
213 }
214
215 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
216 inode, file->f_flags, full_path));
217 desiredAccess = cifs_convert_flags(file->f_flags);
218
219/*********************************************************************
220 * open flag mapping table:
221 *
222 * POSIX Flag CIFS Disposition
223 * ---------- ----------------
224 * O_CREAT FILE_OPEN_IF
225 * O_CREAT | O_EXCL FILE_CREATE
226 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
227 * O_TRUNC FILE_OVERWRITE
228 * none of the above FILE_OPEN
229 *
230 * Note that there is not a direct match between disposition
231 * FILE_SUPERSEDE (ie create whether or not file exists although
232 * O_CREAT | O_TRUNC is similar but truncates the existing
233 * file rather than creating a new file as FILE_SUPERSEDE does
234 * (which uses the attributes / metadata passed in on open call)
235 *?
236 *? O_SYNC is a reasonable match to CIFS writethrough flag
237 *? and the read write flags match reasonably. O_LARGEFILE
238 *? is irrelevant because largefile support is always used
239 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
240 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
241 *********************************************************************/
242
243 disposition = cifs_get_disposition(file->f_flags);
244
245 if (oplockEnabled)
246 oplock = REQ_OPLOCK;
247 else
248 oplock = FALSE;
249
250 /* BB pass O_SYNC flag through on file attributes .. BB */
251
252 /* Also refresh inode by passing in file_info buf returned by SMBOpen
253 and calling get_inode_info with returned buf (at least helps
254 non-Unix server case) */
255
256 /* BB we can not do this if this is the second open of a file
257 and the first handle has writebehind data, we might be
258 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
259 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
260 if (!buf) {
261 rc = -ENOMEM;
262 goto out;
263 }
264 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
265 CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700266 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
267 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frencha9d02ad2005-08-24 23:06:05 -0700268 if (rc == -EIO) {
269 /* Old server, try legacy style OpenX */
270 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
271 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
272 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
273 & CIFS_MOUNT_MAP_SPECIAL_CHR);
274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 if (rc) {
276 cFYI(1, ("cifs_open returned 0x%x ", rc));
277 goto out;
278 }
279 file->private_data =
280 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
281 if (file->private_data == NULL) {
282 rc = -ENOMEM;
283 goto out;
284 }
285 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
286 write_lock(&file->f_owner.lock);
287 write_lock(&GlobalSMBSeslock);
288 list_add(&pCifsFile->tlist, &pTcon->openFileList);
289
290 pCifsInode = CIFS_I(file->f_dentry->d_inode);
291 if (pCifsInode) {
292 rc = cifs_open_inode_helper(inode, file, pCifsInode,
293 pCifsFile, pTcon,
294 &oplock, buf, full_path, xid);
295 } else {
296 write_unlock(&GlobalSMBSeslock);
297 write_unlock(&file->f_owner.lock);
298 }
299
300 if (oplock & CIFS_CREATE_ACTION) {
301 /* time to set mode which we can not set earlier due to
302 problems creating new read-only files */
303 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
304 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
305 inode->i_mode,
306 (__u64)-1, (__u64)-1, 0 /* dev */,
Steve French737b7582005-04-28 22:41:06 -0700307 cifs_sb->local_nls,
308 cifs_sb->mnt_cifs_flags &
309 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 } else {
311 /* BB implement via Windows security descriptors eg
312 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
313 -1, -1, local_nls);
314 in the meantime could set r/o dos attribute when
315 perms are eg: mode & 0222 == 0 */
316 }
317 }
318
319out:
320 kfree(buf);
321 kfree(full_path);
322 FreeXid(xid);
323 return rc;
324}
325
326/* Try to reaquire byte range locks that were released when session */
327/* to server was lost */
328static int cifs_relock_file(struct cifsFileInfo *cifsFile)
329{
330 int rc = 0;
331
332/* BB list all locks open on this file and relock */
333
334 return rc;
335}
336
337static int cifs_reopen_file(struct inode *inode, struct file *file,
338 int can_flush)
339{
340 int rc = -EACCES;
341 int xid, oplock;
342 struct cifs_sb_info *cifs_sb;
343 struct cifsTconInfo *pTcon;
344 struct cifsFileInfo *pCifsFile;
345 struct cifsInodeInfo *pCifsInode;
346 char *full_path = NULL;
347 int desiredAccess;
348 int disposition = FILE_OPEN;
349 __u16 netfid;
350
351 if (inode == NULL)
352 return -EBADF;
353 if (file->private_data) {
354 pCifsFile = (struct cifsFileInfo *)file->private_data;
355 } else
356 return -EBADF;
357
358 xid = GetXid();
359 down(&pCifsFile->fh_sem);
360 if (pCifsFile->invalidHandle == FALSE) {
361 up(&pCifsFile->fh_sem);
362 FreeXid(xid);
363 return 0;
364 }
365
366 if (file->f_dentry == NULL) {
367 up(&pCifsFile->fh_sem);
368 cFYI(1, ("failed file reopen, no valid name if dentry freed"));
369 FreeXid(xid);
370 return -EBADF;
371 }
372 cifs_sb = CIFS_SB(inode->i_sb);
373 pTcon = cifs_sb->tcon;
374/* can not grab rename sem here because various ops, including
375 those that already have the rename sem can end up causing writepage
376 to get called and if the server was down that means we end up here,
377 and we can never tell if the caller already has the rename_sem */
Steve French7f573562005-08-30 11:32:14 -0700378 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (full_path == NULL) {
380 up(&pCifsFile->fh_sem);
381 FreeXid(xid);
382 return -ENOMEM;
383 }
384
385 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
386 inode, file->f_flags,full_path));
387 desiredAccess = cifs_convert_flags(file->f_flags);
388
389 if (oplockEnabled)
390 oplock = REQ_OPLOCK;
391 else
392 oplock = FALSE;
393
394 /* Can not refresh inode by passing in file_info buf to be returned
395 by SMBOpen and then calling get_inode_info with returned buf
396 since file might have write behind data that needs to be flushed
397 and server version of file size can be stale. If we knew for sure
398 that inode was not dirty locally we could do this */
399
400/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
401 if (buf == 0) {
402 up(&pCifsFile->fh_sem);
403 kfree(full_path);
404 FreeXid(xid);
405 return -ENOMEM;
406 } */
407 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
408 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700409 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
410 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if (rc) {
412 up(&pCifsFile->fh_sem);
413 cFYI(1, ("cifs_open returned 0x%x ", rc));
414 cFYI(1, ("oplock: %d ", oplock));
415 } else {
416 pCifsFile->netfid = netfid;
417 pCifsFile->invalidHandle = FALSE;
418 up(&pCifsFile->fh_sem);
419 pCifsInode = CIFS_I(inode);
420 if (pCifsInode) {
421 if (can_flush) {
422 filemap_fdatawrite(inode->i_mapping);
423 filemap_fdatawait(inode->i_mapping);
424 /* temporarily disable caching while we
425 go to server to get inode info */
426 pCifsInode->clientCanCacheAll = FALSE;
427 pCifsInode->clientCanCacheRead = FALSE;
428 if (pTcon->ses->capabilities & CAP_UNIX)
429 rc = cifs_get_inode_info_unix(&inode,
430 full_path, inode->i_sb, xid);
431 else
432 rc = cifs_get_inode_info(&inode,
433 full_path, NULL, inode->i_sb,
434 xid);
435 } /* else we are writing out data to server already
436 and could deadlock if we tried to flush data, and
437 since we do not know if we have data that would
438 invalidate the current end of file on the server
439 we can not go to the server to get the new inod
440 info */
441 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
442 pCifsInode->clientCanCacheAll = TRUE;
443 pCifsInode->clientCanCacheRead = TRUE;
444 cFYI(1, ("Exclusive Oplock granted on inode %p",
445 file->f_dentry->d_inode));
446 } else if ((oplock & 0xF) == OPLOCK_READ) {
447 pCifsInode->clientCanCacheRead = TRUE;
448 pCifsInode->clientCanCacheAll = FALSE;
449 } else {
450 pCifsInode->clientCanCacheRead = FALSE;
451 pCifsInode->clientCanCacheAll = FALSE;
452 }
453 cifs_relock_file(pCifsFile);
454 }
455 }
456
457 kfree(full_path);
458 FreeXid(xid);
459 return rc;
460}
461
462int cifs_close(struct inode *inode, struct file *file)
463{
464 int rc = 0;
465 int xid;
466 struct cifs_sb_info *cifs_sb;
467 struct cifsTconInfo *pTcon;
468 struct cifsFileInfo *pSMBFile =
469 (struct cifsFileInfo *)file->private_data;
470
471 xid = GetXid();
472
473 cifs_sb = CIFS_SB(inode->i_sb);
474 pTcon = cifs_sb->tcon;
475 if (pSMBFile) {
476 pSMBFile->closePend = TRUE;
477 write_lock(&file->f_owner.lock);
478 if (pTcon) {
479 /* no sense reconnecting to close a file that is
480 already closed */
481 if (pTcon->tidStatus != CifsNeedReconnect) {
Steve French23e7dd72005-10-20 13:44:56 -0700482 int timeout = 2;
483 while((atomic_read(&pSMBFile->wrtPending) != 0)
484 && (timeout < 1000) ) {
485 /* Give write a better chance to get to
486 server ahead of the close. We do not
487 want to add a wait_q here as it would
488 increase the memory utilization as
489 the struct would be in each open file,
490 but this should give enough time to
491 clear the socket */
Steve Frenchc119b872005-11-18 12:27:27 -0800492 write_unlock(&file->f_owner.lock);
Steve French23e7dd72005-10-20 13:44:56 -0700493 cERROR(1,("close with pending writes"));
494 msleep(timeout);
Steve Frenchc119b872005-11-18 12:27:27 -0800495 write_lock(&file->f_owner.lock);
Steve French23e7dd72005-10-20 13:44:56 -0700496 timeout *= 4;
497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 write_unlock(&file->f_owner.lock);
499 rc = CIFSSMBClose(xid, pTcon,
500 pSMBFile->netfid);
501 write_lock(&file->f_owner.lock);
502 }
503 }
Steve Frenchcbe04762005-04-28 22:41:05 -0700504 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 list_del(&pSMBFile->flist);
506 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700507 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 write_unlock(&file->f_owner.lock);
509 kfree(pSMBFile->search_resume_name);
510 kfree(file->private_data);
511 file->private_data = NULL;
512 } else
513 rc = -EBADF;
514
515 if (list_empty(&(CIFS_I(inode)->openFileList))) {
516 cFYI(1, ("closing last open instance for inode %p", inode));
517 /* if the file is not open we do not know if we can cache info
518 on this inode, much less write behind and read ahead */
519 CIFS_I(inode)->clientCanCacheRead = FALSE;
520 CIFS_I(inode)->clientCanCacheAll = FALSE;
521 }
522 if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
523 rc = CIFS_I(inode)->write_behind_rc;
524 FreeXid(xid);
525 return rc;
526}
527
528int cifs_closedir(struct inode *inode, struct file *file)
529{
530 int rc = 0;
531 int xid;
532 struct cifsFileInfo *pCFileStruct =
533 (struct cifsFileInfo *)file->private_data;
534 char *ptmp;
535
536 cFYI(1, ("Closedir inode = 0x%p with ", inode));
537
538 xid = GetXid();
539
540 if (pCFileStruct) {
541 struct cifsTconInfo *pTcon;
542 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
543
544 pTcon = cifs_sb->tcon;
545
546 cFYI(1, ("Freeing private data in close dir"));
Steve French31ca3bc2005-04-28 22:41:11 -0700547 if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
548 (pCFileStruct->invalidHandle == FALSE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 pCFileStruct->invalidHandle = TRUE;
550 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
551 cFYI(1, ("Closing uncompleted readdir with rc %d",
552 rc));
553 /* not much we can do if it fails anyway, ignore rc */
554 rc = 0;
555 }
556 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
557 if (ptmp) {
558 /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir"));
559 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
560 cifs_buf_release(ptmp);
561 }
562 ptmp = pCFileStruct->search_resume_name;
563 if (ptmp) {
564 /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir"));
565 pCFileStruct->search_resume_name = NULL;
566 kfree(ptmp);
567 }
568 kfree(file->private_data);
569 file->private_data = NULL;
570 }
571 /* BB can we lock the filestruct while this is going on? */
572 FreeXid(xid);
573 return rc;
574}
575
576int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
577{
578 int rc, xid;
579 __u32 lockType = LOCKING_ANDX_LARGE_FILES;
580 __u32 numLock = 0;
581 __u32 numUnlock = 0;
582 __u64 length;
583 int wait_flag = FALSE;
584 struct cifs_sb_info *cifs_sb;
585 struct cifsTconInfo *pTcon;
586
587 length = 1 + pfLock->fl_end - pfLock->fl_start;
588 rc = -EACCES;
589 xid = GetXid();
590
591 cFYI(1, ("Lock parm: 0x%x flockflags: "
592 "0x%x flocktype: 0x%x start: %lld end: %lld",
593 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
594 pfLock->fl_end));
595
596 if (pfLock->fl_flags & FL_POSIX)
597 cFYI(1, ("Posix "));
598 if (pfLock->fl_flags & FL_FLOCK)
599 cFYI(1, ("Flock "));
600 if (pfLock->fl_flags & FL_SLEEP) {
601 cFYI(1, ("Blocking lock "));
602 wait_flag = TRUE;
603 }
604 if (pfLock->fl_flags & FL_ACCESS)
605 cFYI(1, ("Process suspended by mandatory locking - "
606 "not implemented yet "));
607 if (pfLock->fl_flags & FL_LEASE)
608 cFYI(1, ("Lease on file - not implemented yet"));
609 if (pfLock->fl_flags &
610 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
611 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
612
613 if (pfLock->fl_type == F_WRLCK) {
614 cFYI(1, ("F_WRLCK "));
615 numLock = 1;
616 } else if (pfLock->fl_type == F_UNLCK) {
617 cFYI(1, ("F_UNLCK "));
618 numUnlock = 1;
619 } else if (pfLock->fl_type == F_RDLCK) {
620 cFYI(1, ("F_RDLCK "));
621 lockType |= LOCKING_ANDX_SHARED_LOCK;
622 numLock = 1;
623 } else if (pfLock->fl_type == F_EXLCK) {
624 cFYI(1, ("F_EXLCK "));
625 numLock = 1;
626 } else if (pfLock->fl_type == F_SHLCK) {
627 cFYI(1, ("F_SHLCK "));
628 lockType |= LOCKING_ANDX_SHARED_LOCK;
629 numLock = 1;
630 } else
631 cFYI(1, ("Unknown type of lock "));
632
633 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
634 pTcon = cifs_sb->tcon;
635
636 if (file->private_data == NULL) {
637 FreeXid(xid);
638 return -EBADF;
639 }
640
641 if (IS_GETLK(cmd)) {
642 rc = CIFSSMBLock(xid, pTcon,
643 ((struct cifsFileInfo *)file->
644 private_data)->netfid,
645 length,
646 pfLock->fl_start, 0, 1, lockType,
647 0 /* wait flag */ );
648 if (rc == 0) {
649 rc = CIFSSMBLock(xid, pTcon,
650 ((struct cifsFileInfo *) file->
651 private_data)->netfid,
652 length,
653 pfLock->fl_start, 1 /* numUnlock */ ,
654 0 /* numLock */ , lockType,
655 0 /* wait flag */ );
656 pfLock->fl_type = F_UNLCK;
657 if (rc != 0)
658 cERROR(1, ("Error unlocking previously locked "
659 "range %d during test of lock ",
660 rc));
661 rc = 0;
662
663 } else {
664 /* if rc == ERR_SHARING_VIOLATION ? */
665 rc = 0; /* do not change lock type to unlock
666 since range in use */
667 }
668
669 FreeXid(xid);
670 return rc;
671 }
672
673 rc = CIFSSMBLock(xid, pTcon,
674 ((struct cifsFileInfo *) file->private_data)->
675 netfid, length,
676 pfLock->fl_start, numUnlock, numLock, lockType,
677 wait_flag);
Steve Frenchd634cc12005-08-26 14:42:59 -0500678 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 posix_lock_file_wait(file, pfLock);
680 FreeXid(xid);
681 return rc;
682}
683
684ssize_t cifs_user_write(struct file *file, const char __user *write_data,
685 size_t write_size, loff_t *poffset)
686{
687 int rc = 0;
688 unsigned int bytes_written = 0;
689 unsigned int total_written;
690 struct cifs_sb_info *cifs_sb;
691 struct cifsTconInfo *pTcon;
692 int xid, long_op;
693 struct cifsFileInfo *open_file;
694
695 if (file->f_dentry == NULL)
696 return -EBADF;
697
698 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
699 if (cifs_sb == NULL)
700 return -EBADF;
701
702 pTcon = cifs_sb->tcon;
703
704 /* cFYI(1,
705 (" write %d bytes to offset %lld of %s", write_size,
706 *poffset, file->f_dentry->d_name.name)); */
707
708 if (file->private_data == NULL)
709 return -EBADF;
710 else
711 open_file = (struct cifsFileInfo *) file->private_data;
712
713 xid = GetXid();
714 if (file->f_dentry->d_inode == NULL) {
715 FreeXid(xid);
716 return -EBADF;
717 }
718
719 if (*poffset > file->f_dentry->d_inode->i_size)
720 long_op = 2; /* writes past end of file can take a long time */
721 else
722 long_op = 1;
723
724 for (total_written = 0; write_size > total_written;
725 total_written += bytes_written) {
726 rc = -EAGAIN;
727 while (rc == -EAGAIN) {
728 if (file->private_data == NULL) {
729 /* file has been closed on us */
730 FreeXid(xid);
731 /* if we have gotten here we have written some data
732 and blocked, and the file has been freed on us while
733 we blocked so return what we managed to write */
734 return total_written;
735 }
736 if (open_file->closePend) {
737 FreeXid(xid);
738 if (total_written)
739 return total_written;
740 else
741 return -EBADF;
742 }
743 if (open_file->invalidHandle) {
744 if ((file->f_dentry == NULL) ||
745 (file->f_dentry->d_inode == NULL)) {
746 FreeXid(xid);
747 return total_written;
748 }
749 /* we could deadlock if we called
750 filemap_fdatawait from here so tell
751 reopen_file not to flush data to server
752 now */
753 rc = cifs_reopen_file(file->f_dentry->d_inode,
754 file, FALSE);
755 if (rc != 0)
756 break;
757 }
758
759 rc = CIFSSMBWrite(xid, pTcon,
760 open_file->netfid,
761 min_t(const int, cifs_sb->wsize,
762 write_size - total_written),
763 *poffset, &bytes_written,
764 NULL, write_data + total_written, long_op);
765 }
766 if (rc || (bytes_written == 0)) {
767 if (total_written)
768 break;
769 else {
770 FreeXid(xid);
771 return rc;
772 }
773 } else
774 *poffset += bytes_written;
775 long_op = FALSE; /* subsequent writes fast -
776 15 seconds is plenty */
777 }
778
Steve Frencha4544342005-08-24 13:59:35 -0700779 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 /* since the write may have blocked check these pointers again */
782 if (file->f_dentry) {
783 if (file->f_dentry->d_inode) {
784 struct inode *inode = file->f_dentry->d_inode;
785 inode->i_ctime = inode->i_mtime =
786 current_fs_time(inode->i_sb);
787 if (total_written > 0) {
788 if (*poffset > file->f_dentry->d_inode->i_size)
789 i_size_write(file->f_dentry->d_inode,
790 *poffset);
791 }
792 mark_inode_dirty_sync(file->f_dentry->d_inode);
793 }
794 }
795 FreeXid(xid);
796 return total_written;
797}
798
799static ssize_t cifs_write(struct file *file, const char *write_data,
800 size_t write_size, loff_t *poffset)
801{
802 int rc = 0;
803 unsigned int bytes_written = 0;
804 unsigned int total_written;
805 struct cifs_sb_info *cifs_sb;
806 struct cifsTconInfo *pTcon;
807 int xid, long_op;
808 struct cifsFileInfo *open_file;
809
810 if (file->f_dentry == NULL)
811 return -EBADF;
812
813 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
814 if (cifs_sb == NULL)
815 return -EBADF;
816
817 pTcon = cifs_sb->tcon;
818
Steve Frenchab2f2182005-09-15 20:44:50 -0700819 cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
820 *poffset, file->f_dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 if (file->private_data == NULL)
823 return -EBADF;
824 else
825 open_file = (struct cifsFileInfo *)file->private_data;
826
827 xid = GetXid();
828 if (file->f_dentry->d_inode == NULL) {
829 FreeXid(xid);
830 return -EBADF;
831 }
832
833 if (*poffset > file->f_dentry->d_inode->i_size)
834 long_op = 2; /* writes past end of file can take a long time */
835 else
836 long_op = 1;
837
838 for (total_written = 0; write_size > total_written;
839 total_written += bytes_written) {
840 rc = -EAGAIN;
841 while (rc == -EAGAIN) {
842 if (file->private_data == NULL) {
843 /* file has been closed on us */
844 FreeXid(xid);
845 /* if we have gotten here we have written some data
846 and blocked, and the file has been freed on us
847 while we blocked so return what we managed to
848 write */
849 return total_written;
850 }
851 if (open_file->closePend) {
852 FreeXid(xid);
853 if (total_written)
854 return total_written;
855 else
856 return -EBADF;
857 }
858 if (open_file->invalidHandle) {
859 if ((file->f_dentry == NULL) ||
860 (file->f_dentry->d_inode == NULL)) {
861 FreeXid(xid);
862 return total_written;
863 }
864 /* we could deadlock if we called
865 filemap_fdatawait from here so tell
866 reopen_file not to flush data to
867 server now */
868 rc = cifs_reopen_file(file->f_dentry->d_inode,
869 file, FALSE);
870 if (rc != 0)
871 break;
872 }
Steve French0c0ff092005-06-23 19:31:17 -0500873#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500874 /* BB FIXME We can not sign across two buffers yet */
Steve French0c0ff092005-06-23 19:31:17 -0500875 if((experimEnabled) && ((pTcon->ses->server->secMode &
876 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
Steve French3e844692005-10-03 13:37:24 -0700877 struct kvec iov[2];
878 unsigned int len;
879
Steve French0ae0efa2005-10-10 10:57:19 -0700880 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -0700881 write_size - total_written);
882 /* iov[0] is reserved for smb header */
883 iov[1].iov_base = (char *)write_data +
884 total_written;
885 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500886 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -0700887 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500888 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -0700889 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500890 } else
891 /* BB FIXME fixup indentation of line below */
892#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 rc = CIFSSMBWrite(xid, pTcon,
894 open_file->netfid,
895 min_t(const int, cifs_sb->wsize,
896 write_size - total_written),
897 *poffset, &bytes_written,
898 write_data + total_written, NULL, long_op);
899 }
900 if (rc || (bytes_written == 0)) {
901 if (total_written)
902 break;
903 else {
904 FreeXid(xid);
905 return rc;
906 }
907 } else
908 *poffset += bytes_written;
909 long_op = FALSE; /* subsequent writes fast -
910 15 seconds is plenty */
911 }
912
Steve Frencha4544342005-08-24 13:59:35 -0700913 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 /* since the write may have blocked check these pointers again */
916 if (file->f_dentry) {
917 if (file->f_dentry->d_inode) {
918 file->f_dentry->d_inode->i_ctime =
919 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
920 if (total_written > 0) {
921 if (*poffset > file->f_dentry->d_inode->i_size)
922 i_size_write(file->f_dentry->d_inode,
923 *poffset);
924 }
925 mark_inode_dirty_sync(file->f_dentry->d_inode);
926 }
927 }
928 FreeXid(xid);
929 return total_written;
930}
931
Steve Frenchdd99cd82005-10-05 19:32:49 -0700932struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -0700933{
934 struct cifsFileInfo *open_file;
Steve Frenchdd99cd82005-10-05 19:32:49 -0700935 int rc;
Steve French6148a742005-10-05 12:23:19 -0700936
937 read_lock(&GlobalSMBSeslock);
938 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
939 if (open_file->closePend)
940 continue;
941 if (open_file->pfile &&
942 ((open_file->pfile->f_flags & O_RDWR) ||
943 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -0700944 atomic_inc(&open_file->wrtPending);
Steve French6148a742005-10-05 12:23:19 -0700945 read_unlock(&GlobalSMBSeslock);
Steve French0ae0efa2005-10-10 10:57:19 -0700946 if((open_file->invalidHandle) &&
Steve French23e7dd72005-10-20 13:44:56 -0700947 (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
Steve Frenchdd99cd82005-10-05 19:32:49 -0700948 rc = cifs_reopen_file(&cifs_inode->vfs_inode,
Steve French37c0eb42005-10-05 14:50:29 -0700949 open_file->pfile, FALSE);
950 /* if it fails, try another handle - might be */
951 /* dangerous to hold up writepages with retry */
952 if(rc) {
Steve French4a771182005-10-05 15:14:33 -0700953 cFYI(1,("failed on reopen file in wp"));
Steve French37c0eb42005-10-05 14:50:29 -0700954 read_lock(&GlobalSMBSeslock);
Steve French23e7dd72005-10-20 13:44:56 -0700955 /* can not use this handle, no write
956 pending on this one after all */
957 atomic_dec
958 (&open_file->wrtPending);
Steve French37c0eb42005-10-05 14:50:29 -0700959 continue;
960 }
961 }
Steve French6148a742005-10-05 12:23:19 -0700962 return open_file;
963 }
964 }
965 read_unlock(&GlobalSMBSeslock);
966 return NULL;
967}
968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
970{
971 struct address_space *mapping = page->mapping;
972 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
973 char *write_data;
974 int rc = -EFAULT;
975 int bytes_written = 0;
976 struct cifs_sb_info *cifs_sb;
977 struct cifsTconInfo *pTcon;
978 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -0700979 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 if (!mapping || !mapping->host)
982 return -EFAULT;
983
984 inode = page->mapping->host;
985 cifs_sb = CIFS_SB(inode->i_sb);
986 pTcon = cifs_sb->tcon;
987
988 offset += (loff_t)from;
989 write_data = kmap(page);
990 write_data += from;
991
992 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
993 kunmap(page);
994 return -EIO;
995 }
996
997 /* racing with truncate? */
998 if (offset > mapping->host->i_size) {
999 kunmap(page);
1000 return 0; /* don't care */
1001 }
1002
1003 /* check to make sure that we are not extending the file */
1004 if (mapping->host->i_size - offset < (loff_t)to)
1005 to = (unsigned)(mapping->host->i_size - offset);
1006
Steve French6148a742005-10-05 12:23:19 -07001007 open_file = find_writable_file(CIFS_I(mapping->host));
1008 if (open_file) {
1009 bytes_written = cifs_write(open_file->pfile, write_data,
1010 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001011 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001013 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
1014 if ((bytes_written > 0) && (offset)) {
1015 rc = 0;
1016 } else if (bytes_written < 0) {
1017 if (rc != -EBADF)
1018 rc = bytes_written;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 }
Steve French6148a742005-10-05 12:23:19 -07001020 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 cFYI(1, ("No writeable filehandles for inode"));
1022 rc = -EIO;
1023 }
1024
1025 kunmap(page);
1026 return rc;
1027}
1028
Steve French37c0eb42005-10-05 14:50:29 -07001029#ifdef CONFIG_CIFS_EXPERIMENTAL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001031 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
Steve French37c0eb42005-10-05 14:50:29 -07001033 struct backing_dev_info *bdi = mapping->backing_dev_info;
1034 unsigned int bytes_to_write;
1035 unsigned int bytes_written;
1036 struct cifs_sb_info *cifs_sb;
1037 int done = 0;
1038 pgoff_t end = -1;
1039 pgoff_t index;
1040 int is_range = 0;
1041 struct kvec iov[32];
Steve French84d2f072005-10-12 15:32:05 -07001042 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001043 int n_iov = 0;
1044 pgoff_t next;
1045 int nr_pages;
1046 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001047 struct cifsFileInfo *open_file;
Steve French37c0eb42005-10-05 14:50:29 -07001048 struct page *page;
1049 struct pagevec pvec;
1050 int rc = 0;
1051 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 int xid;
1053
Steve French37c0eb42005-10-05 14:50:29 -07001054 cifs_sb = CIFS_SB(mapping->host->i_sb);
1055
1056 /*
1057 * If wsize is smaller that the page cache size, default to writing
1058 * one page at a time via cifs_writepage
1059 */
1060 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1061 return generic_writepages(mapping, wbc);
1062
Steve French4a771182005-10-05 15:14:33 -07001063 /* BB FIXME we do not have code to sign across multiple buffers yet,
1064 so go to older writepage style write which we can sign if needed */
1065 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1066 if(cifs_sb->tcon->ses->server->secMode &
1067 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1068 return generic_writepages(mapping, wbc);
1069
Steve French37c0eb42005-10-05 14:50:29 -07001070 /*
1071 * BB: Is this meaningful for a non-block-device file system?
1072 * If it is, we should test it again after we do I/O
1073 */
1074 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1075 wbc->encountered_congestion = 1;
1076 return 0;
1077 }
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 xid = GetXid();
1080
Steve French37c0eb42005-10-05 14:50:29 -07001081 pagevec_init(&pvec, 0);
1082 if (wbc->sync_mode == WB_SYNC_NONE)
1083 index = mapping->writeback_index; /* Start from prev offset */
1084 else {
1085 index = 0;
1086 scanned = 1;
1087 }
1088 if (wbc->start || wbc->end) {
1089 index = wbc->start >> PAGE_CACHE_SHIFT;
1090 end = wbc->end >> PAGE_CACHE_SHIFT;
1091 is_range = 1;
1092 scanned = 1;
1093 }
1094retry:
1095 while (!done && (index <= end) &&
1096 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1097 PAGECACHE_TAG_DIRTY,
1098 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1099 int first;
1100 unsigned int i;
1101
Steve French37c0eb42005-10-05 14:50:29 -07001102 first = -1;
1103 next = 0;
1104 n_iov = 0;
1105 bytes_to_write = 0;
1106
1107 for (i = 0; i < nr_pages; i++) {
1108 page = pvec.pages[i];
1109 /*
1110 * At this point we hold neither mapping->tree_lock nor
1111 * lock on the page itself: the page may be truncated or
1112 * invalidated (changing page->mapping to NULL), or even
1113 * swizzled back from swapper_space to tmpfs file
1114 * mapping
1115 */
1116
1117 if (first < 0)
1118 lock_page(page);
1119 else if (TestSetPageLocked(page))
1120 break;
1121
1122 if (unlikely(page->mapping != mapping)) {
1123 unlock_page(page);
1124 break;
1125 }
1126
1127 if (unlikely(is_range) && (page->index > end)) {
1128 done = 1;
1129 unlock_page(page);
1130 break;
1131 }
1132
1133 if (next && (page->index != next)) {
1134 /* Not next consecutive page */
1135 unlock_page(page);
1136 break;
1137 }
1138
1139 if (wbc->sync_mode != WB_SYNC_NONE)
1140 wait_on_page_writeback(page);
1141
1142 if (PageWriteback(page) ||
1143 !test_clear_page_dirty(page)) {
1144 unlock_page(page);
1145 break;
1146 }
Steve French84d2f072005-10-12 15:32:05 -07001147
1148 if (page_offset(page) >= mapping->host->i_size) {
1149 done = 1;
1150 unlock_page(page);
1151 break;
1152 }
1153
Steve French37c0eb42005-10-05 14:50:29 -07001154 /*
1155 * BB can we get rid of this? pages are held by pvec
1156 */
1157 page_cache_get(page);
1158
Steve French84d2f072005-10-12 15:32:05 -07001159 len = min(mapping->host->i_size - page_offset(page),
1160 (loff_t)PAGE_CACHE_SIZE);
1161
Steve French37c0eb42005-10-05 14:50:29 -07001162 /* reserve iov[0] for the smb header */
1163 n_iov++;
1164 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001165 iov[n_iov].iov_len = len;
1166 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001167
1168 if (first < 0) {
1169 first = i;
1170 offset = page_offset(page);
1171 }
1172 next = page->index + 1;
1173 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1174 break;
1175 }
1176 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001177 /* Search for a writable handle every time we call
1178 * CIFSSMBWrite2. We can't rely on the last handle
1179 * we used to still be valid
1180 */
1181 open_file = find_writable_file(CIFS_I(mapping->host));
1182 if (!open_file) {
1183 cERROR(1, ("No writable handles for inode"));
1184 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001185 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001186 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1187 open_file->netfid,
1188 bytes_to_write, offset,
1189 &bytes_written, iov, n_iov,
1190 1);
1191 atomic_dec(&open_file->wrtPending);
1192 if (rc || bytes_written < bytes_to_write) {
1193 cERROR(1,("Write2 ret %d, written = %d",
1194 rc, bytes_written));
1195 /* BB what if continued retry is
1196 requested via mount flags? */
1197 set_bit(AS_EIO, &mapping->flags);
1198 SetPageError(page);
1199 } else {
1200 cifs_stats_bytes_written(cifs_sb->tcon,
1201 bytes_written);
1202 }
Steve French37c0eb42005-10-05 14:50:29 -07001203 }
1204 for (i = 0; i < n_iov; i++) {
1205 page = pvec.pages[first + i];
1206 kunmap(page);
1207 unlock_page(page);
1208 page_cache_release(page);
1209 }
1210 if ((wbc->nr_to_write -= n_iov) <= 0)
1211 done = 1;
1212 index = next;
1213 }
1214 pagevec_release(&pvec);
1215 }
1216 if (!scanned && !done) {
1217 /*
1218 * We hit the last page and there is more work to be done: wrap
1219 * back to the start of the file
1220 */
1221 scanned = 1;
1222 index = 0;
1223 goto retry;
1224 }
1225 if (!is_range)
1226 mapping->writeback_index = index;
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 FreeXid(xid);
Steve French37c0eb42005-10-05 14:50:29 -07001229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 return rc;
1231}
1232#endif
1233
1234static int cifs_writepage(struct page* page, struct writeback_control *wbc)
1235{
1236 int rc = -EFAULT;
1237 int xid;
1238
1239 xid = GetXid();
1240/* BB add check for wbc flags */
1241 page_cache_get(page);
1242 if (!PageUptodate(page)) {
1243 cFYI(1, ("ppw - page not up to date"));
1244 }
1245
1246 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1247 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1248 unlock_page(page);
1249 page_cache_release(page);
1250 FreeXid(xid);
1251 return rc;
1252}
1253
1254static int cifs_commit_write(struct file *file, struct page *page,
1255 unsigned offset, unsigned to)
1256{
1257 int xid;
1258 int rc = 0;
1259 struct inode *inode = page->mapping->host;
1260 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1261 char *page_data;
1262
1263 xid = GetXid();
1264 cFYI(1, ("commit write for page %p up to position %lld for %d",
1265 page, position, to));
1266 if (position > inode->i_size) {
1267 i_size_write(inode, position);
1268 /* if (file->private_data == NULL) {
1269 rc = -EBADF;
1270 } else {
1271 open_file = (struct cifsFileInfo *)file->private_data;
1272 cifs_sb = CIFS_SB(inode->i_sb);
1273 rc = -EAGAIN;
1274 while (rc == -EAGAIN) {
1275 if ((open_file->invalidHandle) &&
1276 (!open_file->closePend)) {
1277 rc = cifs_reopen_file(
1278 file->f_dentry->d_inode, file);
1279 if (rc != 0)
1280 break;
1281 }
1282 if (!open_file->closePend) {
1283 rc = CIFSSMBSetFileSize(xid,
1284 cifs_sb->tcon, position,
1285 open_file->netfid,
1286 open_file->pid, FALSE);
1287 } else {
1288 rc = -EBADF;
1289 break;
1290 }
1291 }
1292 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1293 } */
1294 }
1295 if (!PageUptodate(page)) {
1296 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1297 /* can not rely on (or let) writepage write this data */
1298 if (to < offset) {
1299 cFYI(1, ("Illegal offsets, can not copy from %d to %d",
1300 offset, to));
1301 FreeXid(xid);
1302 return rc;
1303 }
1304 /* this is probably better than directly calling
1305 partialpage_write since in this function the file handle is
1306 known which we might as well leverage */
1307 /* BB check if anything else missing out of ppw
1308 such as updating last write time */
1309 page_data = kmap(page);
1310 rc = cifs_write(file, page_data + offset, to-offset,
1311 &position);
1312 if (rc > 0)
1313 rc = 0;
1314 /* else if (rc < 0) should we set writebehind rc? */
1315 kunmap(page);
1316 } else {
1317 set_page_dirty(page);
1318 }
1319
1320 FreeXid(xid);
1321 return rc;
1322}
1323
1324int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1325{
1326 int xid;
1327 int rc = 0;
1328 struct inode *inode = file->f_dentry->d_inode;
1329
1330 xid = GetXid();
1331
1332 cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
1333 dentry->d_name.name, datasync));
1334
1335 rc = filemap_fdatawrite(inode->i_mapping);
1336 if (rc == 0)
1337 CIFS_I(inode)->write_behind_rc = 0;
1338 FreeXid(xid);
1339 return rc;
1340}
1341
1342/* static int cifs_sync_page(struct page *page)
1343{
1344 struct address_space *mapping;
1345 struct inode *inode;
1346 unsigned long index = page->index;
1347 unsigned int rpages = 0;
1348 int rc = 0;
1349
1350 cFYI(1, ("sync page %p",page));
1351 mapping = page->mapping;
1352 if (!mapping)
1353 return 0;
1354 inode = mapping->host;
1355 if (!inode)
1356 return 0; */
1357
1358/* fill in rpages then
1359 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1360
1361/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
1362
1363 if (rc < 0)
1364 return rc;
1365 return 0;
1366} */
1367
1368/*
1369 * As file closes, flush all cached write data for this inode checking
1370 * for write behind errors.
1371 */
1372int cifs_flush(struct file *file)
1373{
1374 struct inode * inode = file->f_dentry->d_inode;
1375 int rc = 0;
1376
1377 /* Rather than do the steps manually:
1378 lock the inode for writing
1379 loop through pages looking for write behind data (dirty pages)
1380 coalesce into contiguous 16K (or smaller) chunks to write to server
1381 send to server (prefer in parallel)
1382 deal with writebehind errors
1383 unlock inode for writing
1384 filemapfdatawrite appears easier for the time being */
1385
1386 rc = filemap_fdatawrite(inode->i_mapping);
1387 if (!rc) /* reset wb rc if we were able to write out dirty pages */
1388 CIFS_I(inode)->write_behind_rc = 0;
1389
1390 cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
1391
1392 return rc;
1393}
1394
1395ssize_t cifs_user_read(struct file *file, char __user *read_data,
1396 size_t read_size, loff_t *poffset)
1397{
1398 int rc = -EACCES;
1399 unsigned int bytes_read = 0;
1400 unsigned int total_read = 0;
1401 unsigned int current_read_size;
1402 struct cifs_sb_info *cifs_sb;
1403 struct cifsTconInfo *pTcon;
1404 int xid;
1405 struct cifsFileInfo *open_file;
1406 char *smb_read_data;
1407 char __user *current_offset;
1408 struct smb_com_read_rsp *pSMBr;
1409
1410 xid = GetXid();
1411 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1412 pTcon = cifs_sb->tcon;
1413
1414 if (file->private_data == NULL) {
1415 FreeXid(xid);
1416 return -EBADF;
1417 }
1418 open_file = (struct cifsFileInfo *)file->private_data;
1419
1420 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1421 cFYI(1, ("attempting read on write only file instance"));
1422 }
1423 for (total_read = 0, current_offset = read_data;
1424 read_size > total_read;
1425 total_read += bytes_read, current_offset += bytes_read) {
1426 current_read_size = min_t(const int, read_size - total_read,
1427 cifs_sb->rsize);
1428 rc = -EAGAIN;
1429 smb_read_data = NULL;
1430 while (rc == -EAGAIN) {
1431 if ((open_file->invalidHandle) &&
1432 (!open_file->closePend)) {
1433 rc = cifs_reopen_file(file->f_dentry->d_inode,
1434 file, TRUE);
1435 if (rc != 0)
1436 break;
1437 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001438 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001439 open_file->netfid,
1440 current_read_size, *poffset,
1441 &bytes_read, &smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1443 if (copy_to_user(current_offset,
1444 smb_read_data + 4 /* RFC1001 hdr */
1445 + le16_to_cpu(pSMBr->DataOffset),
1446 bytes_read)) {
1447 rc = -EFAULT;
1448 FreeXid(xid);
1449 return rc;
1450 }
1451 if (smb_read_data) {
1452 cifs_buf_release(smb_read_data);
1453 smb_read_data = NULL;
1454 }
1455 }
1456 if (rc || (bytes_read == 0)) {
1457 if (total_read) {
1458 break;
1459 } else {
1460 FreeXid(xid);
1461 return rc;
1462 }
1463 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001464 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 *poffset += bytes_read;
1466 }
1467 }
1468 FreeXid(xid);
1469 return total_read;
1470}
1471
1472
1473static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1474 loff_t *poffset)
1475{
1476 int rc = -EACCES;
1477 unsigned int bytes_read = 0;
1478 unsigned int total_read;
1479 unsigned int current_read_size;
1480 struct cifs_sb_info *cifs_sb;
1481 struct cifsTconInfo *pTcon;
1482 int xid;
1483 char *current_offset;
1484 struct cifsFileInfo *open_file;
1485
1486 xid = GetXid();
1487 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1488 pTcon = cifs_sb->tcon;
1489
1490 if (file->private_data == NULL) {
1491 FreeXid(xid);
1492 return -EBADF;
1493 }
1494 open_file = (struct cifsFileInfo *)file->private_data;
1495
1496 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1497 cFYI(1, ("attempting read on write only file instance"));
1498
1499 for (total_read = 0, current_offset = read_data;
1500 read_size > total_read;
1501 total_read += bytes_read, current_offset += bytes_read) {
1502 current_read_size = min_t(const int, read_size - total_read,
1503 cifs_sb->rsize);
Steve Frenchf9f5c812005-09-15 23:06:38 -07001504 /* For windows me and 9x we do not want to request more
1505 than it negotiated since it will refuse the read then */
1506 if((pTcon->ses) &&
1507 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1508 current_read_size = min_t(const int, current_read_size,
1509 pTcon->ses->server->maxBuf - 128);
1510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 rc = -EAGAIN;
1512 while (rc == -EAGAIN) {
1513 if ((open_file->invalidHandle) &&
1514 (!open_file->closePend)) {
1515 rc = cifs_reopen_file(file->f_dentry->d_inode,
1516 file, TRUE);
1517 if (rc != 0)
1518 break;
1519 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001520 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001521 open_file->netfid,
1522 current_read_size, *poffset,
1523 &bytes_read, &current_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 }
1525 if (rc || (bytes_read == 0)) {
1526 if (total_read) {
1527 break;
1528 } else {
1529 FreeXid(xid);
1530 return rc;
1531 }
1532 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001533 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 *poffset += bytes_read;
1535 }
1536 }
1537 FreeXid(xid);
1538 return total_read;
1539}
1540
1541int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1542{
1543 struct dentry *dentry = file->f_dentry;
1544 int rc, xid;
1545
1546 xid = GetXid();
1547 rc = cifs_revalidate(dentry);
1548 if (rc) {
1549 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1550 FreeXid(xid);
1551 return rc;
1552 }
1553 rc = generic_file_mmap(file, vma);
1554 FreeXid(xid);
1555 return rc;
1556}
1557
1558
1559static void cifs_copy_cache_pages(struct address_space *mapping,
1560 struct list_head *pages, int bytes_read, char *data,
1561 struct pagevec *plru_pvec)
1562{
1563 struct page *page;
1564 char *target;
1565
1566 while (bytes_read > 0) {
1567 if (list_empty(pages))
1568 break;
1569
1570 page = list_entry(pages->prev, struct page, lru);
1571 list_del(&page->lru);
1572
1573 if (add_to_page_cache(page, mapping, page->index,
1574 GFP_KERNEL)) {
1575 page_cache_release(page);
1576 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001577 data += PAGE_CACHE_SIZE;
1578 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 continue;
1580 }
1581
1582 target = kmap_atomic(page,KM_USER0);
1583
1584 if (PAGE_CACHE_SIZE > bytes_read) {
1585 memcpy(target, data, bytes_read);
1586 /* zero the tail end of this partial page */
1587 memset(target + bytes_read, 0,
1588 PAGE_CACHE_SIZE - bytes_read);
1589 bytes_read = 0;
1590 } else {
1591 memcpy(target, data, PAGE_CACHE_SIZE);
1592 bytes_read -= PAGE_CACHE_SIZE;
1593 }
1594 kunmap_atomic(target, KM_USER0);
1595
1596 flush_dcache_page(page);
1597 SetPageUptodate(page);
1598 unlock_page(page);
1599 if (!pagevec_add(plru_pvec, page))
1600 __pagevec_lru_add(plru_pvec);
1601 data += PAGE_CACHE_SIZE;
1602 }
1603 return;
1604}
1605
1606static int cifs_readpages(struct file *file, struct address_space *mapping,
1607 struct list_head *page_list, unsigned num_pages)
1608{
1609 int rc = -EACCES;
1610 int xid;
1611 loff_t offset;
1612 struct page *page;
1613 struct cifs_sb_info *cifs_sb;
1614 struct cifsTconInfo *pTcon;
1615 int bytes_read = 0;
1616 unsigned int read_size,i;
1617 char *smb_read_data = NULL;
1618 struct smb_com_read_rsp *pSMBr;
1619 struct pagevec lru_pvec;
1620 struct cifsFileInfo *open_file;
1621
1622 xid = GetXid();
1623 if (file->private_data == NULL) {
1624 FreeXid(xid);
1625 return -EBADF;
1626 }
1627 open_file = (struct cifsFileInfo *)file->private_data;
1628 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1629 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 pagevec_init(&lru_pvec, 0);
1632
1633 for (i = 0; i < num_pages; ) {
1634 unsigned contig_pages;
1635 struct page *tmp_page;
1636 unsigned long expected_index;
1637
1638 if (list_empty(page_list))
1639 break;
1640
1641 page = list_entry(page_list->prev, struct page, lru);
1642 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1643
1644 /* count adjacent pages that we will read into */
1645 contig_pages = 0;
1646 expected_index =
1647 list_entry(page_list->prev, struct page, lru)->index;
1648 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1649 if (tmp_page->index == expected_index) {
1650 contig_pages++;
1651 expected_index++;
1652 } else
1653 break;
1654 }
1655 if (contig_pages + i > num_pages)
1656 contig_pages = num_pages - i;
1657
1658 /* for reads over a certain size could initiate async
1659 read ahead */
1660
1661 read_size = contig_pages * PAGE_CACHE_SIZE;
1662 /* Read size needs to be in multiples of one page */
1663 read_size = min_t(const unsigned int, read_size,
1664 cifs_sb->rsize & PAGE_CACHE_MASK);
1665
1666 rc = -EAGAIN;
1667 while (rc == -EAGAIN) {
1668 if ((open_file->invalidHandle) &&
1669 (!open_file->closePend)) {
1670 rc = cifs_reopen_file(file->f_dentry->d_inode,
1671 file, TRUE);
1672 if (rc != 0)
1673 break;
1674 }
1675
Steve Frenchbfa0d752005-08-31 21:50:37 -07001676 rc = CIFSSMBRead(xid, pTcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001677 open_file->netfid,
1678 read_size, offset,
1679 &bytes_read, &smb_read_data);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001680
1681 /* BB more RC checks ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if (rc== -EAGAIN) {
1683 if (smb_read_data) {
1684 cifs_buf_release(smb_read_data);
1685 smb_read_data = NULL;
1686 }
1687 }
1688 }
1689 if ((rc < 0) || (smb_read_data == NULL)) {
1690 cFYI(1, ("Read error in readpages: %d", rc));
1691 /* clean up remaing pages off list */
1692 while (!list_empty(page_list) && (i < num_pages)) {
1693 page = list_entry(page_list->prev, struct page,
1694 lru);
1695 list_del(&page->lru);
1696 page_cache_release(page);
1697 }
1698 break;
1699 } else if (bytes_read > 0) {
1700 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1701 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1702 smb_read_data + 4 /* RFC1001 hdr */ +
1703 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1704
1705 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001706 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1708 i++; /* account for partial page */
1709
1710 /* server copy of file can have smaller size
1711 than client */
1712 /* BB do we need to verify this common case ?
1713 this case is ok - if we are at server EOF
1714 we will hit it on next read */
1715
1716 /* while (!list_empty(page_list) && (i < num_pages)) {
1717 page = list_entry(page_list->prev,
1718 struct page, list);
1719 list_del(&page->list);
1720 page_cache_release(page);
1721 }
1722 break; */
1723 }
1724 } else {
1725 cFYI(1, ("No bytes read (%d) at offset %lld . "
1726 "Cleaning remaining pages from readahead list",
1727 bytes_read, offset));
1728 /* BB turn off caching and do new lookup on
1729 file size at server? */
1730 while (!list_empty(page_list) && (i < num_pages)) {
1731 page = list_entry(page_list->prev, struct page,
1732 lru);
1733 list_del(&page->lru);
1734
1735 /* BB removeme - replace with zero of page? */
1736 page_cache_release(page);
1737 }
1738 break;
1739 }
1740 if (smb_read_data) {
1741 cifs_buf_release(smb_read_data);
1742 smb_read_data = NULL;
1743 }
1744 bytes_read = 0;
1745 }
1746
1747 pagevec_lru_add(&lru_pvec);
1748
1749/* need to free smb_read_data buf before exit */
1750 if (smb_read_data) {
1751 cifs_buf_release(smb_read_data);
1752 smb_read_data = NULL;
1753 }
1754
1755 FreeXid(xid);
1756 return rc;
1757}
1758
1759static int cifs_readpage_worker(struct file *file, struct page *page,
1760 loff_t *poffset)
1761{
1762 char *read_data;
1763 int rc;
1764
1765 page_cache_get(page);
1766 read_data = kmap(page);
1767 /* for reads over a certain size could initiate async read ahead */
1768
1769 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1770
1771 if (rc < 0)
1772 goto io_error;
1773 else
1774 cFYI(1, ("Bytes read %d ",rc));
1775
1776 file->f_dentry->d_inode->i_atime =
1777 current_fs_time(file->f_dentry->d_inode->i_sb);
1778
1779 if (PAGE_CACHE_SIZE > rc)
1780 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1781
1782 flush_dcache_page(page);
1783 SetPageUptodate(page);
1784 rc = 0;
1785
1786io_error:
1787 kunmap(page);
1788 page_cache_release(page);
1789 return rc;
1790}
1791
1792static int cifs_readpage(struct file *file, struct page *page)
1793{
1794 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1795 int rc = -EACCES;
1796 int xid;
1797
1798 xid = GetXid();
1799
1800 if (file->private_data == NULL) {
1801 FreeXid(xid);
1802 return -EBADF;
1803 }
1804
1805 cFYI(1, ("readpage %p at offset %d 0x%x\n",
1806 page, (int)offset, (int)offset));
1807
1808 rc = cifs_readpage_worker(file, page, &offset);
1809
1810 unlock_page(page);
1811
1812 FreeXid(xid);
1813 return rc;
1814}
1815
1816/* We do not want to update the file size from server for inodes
1817 open for write - to avoid races with writepage extending
1818 the file - in the future we could consider allowing
1819 refreshing the inode only on increases in the file size
1820 but this is tricky to do without racing with writebehind
1821 page caching in the current Linux kernel design */
1822int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1823{
Steve French23e7dd72005-10-20 13:44:56 -07001824 struct cifsFileInfo *open_file = NULL;
1825
1826 if (cifsInode)
1827 open_file = find_writable_file(cifsInode);
1828
1829 if(open_file) {
1830 /* there is not actually a write pending so let
1831 this handle go free and allow it to
1832 be closable if needed */
1833 atomic_dec(&open_file->wrtPending);
Steve French6148a742005-10-05 12:23:19 -07001834 return 0;
Steve French23e7dd72005-10-20 13:44:56 -07001835 } else
Steve French6148a742005-10-05 12:23:19 -07001836 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837}
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839static int cifs_prepare_write(struct file *file, struct page *page,
1840 unsigned from, unsigned to)
1841{
1842 int rc = 0;
1843 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1844 cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
1845 if (!PageUptodate(page)) {
1846 /* if (to - from != PAGE_CACHE_SIZE) {
1847 void *kaddr = kmap_atomic(page, KM_USER0);
1848 memset(kaddr, 0, from);
1849 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1850 flush_dcache_page(page);
1851 kunmap_atomic(kaddr, KM_USER0);
1852 } */
1853 /* If we are writing a full page it will be up to date,
1854 no need to read from the server */
1855 if ((to == PAGE_CACHE_SIZE) && (from == 0))
1856 SetPageUptodate(page);
1857
1858 /* might as well read a page, it is fast enough */
1859 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
1860 rc = cifs_readpage_worker(file, page, &offset);
1861 } else {
1862 /* should we try using another file handle if there is one -
1863 how would we lock it to prevent close of that handle
1864 racing with this read?
1865 In any case this will be written out by commit_write */
1866 }
1867 }
1868
1869 /* BB should we pass any errors back?
1870 e.g. if we do not have read access to the file */
1871 return 0;
1872}
1873
1874struct address_space_operations cifs_addr_ops = {
1875 .readpage = cifs_readpage,
1876 .readpages = cifs_readpages,
1877 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07001878#ifdef CONFIG_CIFS_EXPERIMENTAL
1879 .writepages = cifs_writepages,
1880#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 .prepare_write = cifs_prepare_write,
1882 .commit_write = cifs_commit_write,
1883 .set_page_dirty = __set_page_dirty_nobuffers,
1884 /* .sync_page = cifs_sync_page, */
1885 /* .direct_IO = */
1886};