blob: 4b07a8cc4633e918757d66acf92ec885591b07f0 [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)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#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);
Jeremy Allison7ee1af72006-08-02 21:56:33 +000050 init_MUTEX(&private_data->lock_sem);
51 INIT_LIST_HEAD(&private_data->llist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 private_data->pfile = file; /* needed for writepage */
53 private_data->pInode = inode;
54 private_data->invalidHandle = FALSE;
55 private_data->closePend = FALSE;
Steve French23e7dd72005-10-20 13:44:56 -070056 /* we have to track num writers to the inode, since writepages
57 does not tell us which handle the write is for so there can
58 be a close (overlapping with write) of the filehandle that
59 cifs_writepages chose to use */
60 atomic_set(&private_data->wrtPending,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62 return private_data;
63}
64
65static inline int cifs_convert_flags(unsigned int flags)
66{
67 if ((flags & O_ACCMODE) == O_RDONLY)
68 return GENERIC_READ;
69 else if ((flags & O_ACCMODE) == O_WRONLY)
70 return GENERIC_WRITE;
71 else if ((flags & O_ACCMODE) == O_RDWR) {
72 /* GENERIC_ALL is too much permission to request
73 can cause unnecessary access denied on create */
74 /* return GENERIC_ALL; */
75 return (GENERIC_READ | GENERIC_WRITE);
76 }
77
78 return 0x20197;
79}
80
81static inline int cifs_get_disposition(unsigned int flags)
82{
83 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
84 return FILE_CREATE;
85 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
86 return FILE_OVERWRITE_IF;
87 else if ((flags & O_CREAT) == O_CREAT)
88 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +000089 else if ((flags & O_TRUNC) == O_TRUNC)
90 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 else
92 return FILE_OPEN;
93}
94
95/* all arguments to this function must be checked for validity in caller */
96static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
97 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
98 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
99 char *full_path, int xid)
100{
101 struct timespec temp;
102 int rc;
103
104 /* want handles we can use to read with first
105 in the list so we do not have to walk the
106 list to search for one in prepare_write */
107 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
108 list_add_tail(&pCifsFile->flist,
109 &pCifsInode->openFileList);
110 } else {
111 list_add(&pCifsFile->flist,
112 &pCifsInode->openFileList);
113 }
114 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (pCifsInode->clientCanCacheRead) {
116 /* we have the inode open somewhere else
117 no need to discard cache data */
118 goto client_can_cache;
119 }
120
121 /* BB need same check in cifs_create too? */
122 /* if not oplocked, invalidate inode pages if mtime or file
123 size changed */
124 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
125 if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
126 (file->f_dentry->d_inode->i_size ==
127 (loff_t)le64_to_cpu(buf->EndOfFile))) {
128 cFYI(1, ("inode unchanged on server"));
129 } else {
130 if (file->f_dentry->d_inode->i_mapping) {
131 /* BB no need to lock inode until after invalidate
132 since namei code should already have it locked? */
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800133 filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 }
135 cFYI(1, ("invalidating remote inode since open detected it "
136 "changed"));
137 invalidate_remote_inode(file->f_dentry->d_inode);
138 }
139
140client_can_cache:
141 if (pTcon->ses->capabilities & CAP_UNIX)
142 rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
143 full_path, inode->i_sb, xid);
144 else
145 rc = cifs_get_inode_info(&file->f_dentry->d_inode,
146 full_path, buf, inode->i_sb, xid);
147
148 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
149 pCifsInode->clientCanCacheAll = TRUE;
150 pCifsInode->clientCanCacheRead = TRUE;
151 cFYI(1, ("Exclusive Oplock granted on inode %p",
152 file->f_dentry->d_inode));
153 } else if ((*oplock & 0xF) == OPLOCK_READ)
154 pCifsInode->clientCanCacheRead = TRUE;
155
156 return rc;
157}
158
159int cifs_open(struct inode *inode, struct file *file)
160{
161 int rc = -EACCES;
162 int xid, oplock;
163 struct cifs_sb_info *cifs_sb;
164 struct cifsTconInfo *pTcon;
165 struct cifsFileInfo *pCifsFile;
166 struct cifsInodeInfo *pCifsInode;
167 struct list_head *tmp;
168 char *full_path = NULL;
169 int desiredAccess;
170 int disposition;
171 __u16 netfid;
172 FILE_ALL_INFO *buf = NULL;
173
174 xid = GetXid();
175
176 cifs_sb = CIFS_SB(inode->i_sb);
177 pTcon = cifs_sb->tcon;
178
179 if (file->f_flags & O_CREAT) {
180 /* search inode for this file and fill in file->private_data */
181 pCifsInode = CIFS_I(file->f_dentry->d_inode);
182 read_lock(&GlobalSMBSeslock);
183 list_for_each(tmp, &pCifsInode->openFileList) {
184 pCifsFile = list_entry(tmp, struct cifsFileInfo,
185 flist);
186 if ((pCifsFile->pfile == NULL) &&
187 (pCifsFile->pid == current->tgid)) {
188 /* mode set in cifs_create */
189
190 /* needed for writepage */
191 pCifsFile->pfile = file;
192
193 file->private_data = pCifsFile;
194 break;
195 }
196 }
197 read_unlock(&GlobalSMBSeslock);
198 if (file->private_data != NULL) {
199 rc = 0;
200 FreeXid(xid);
201 return rc;
202 } else {
203 if (file->f_flags & O_EXCL)
204 cERROR(1, ("could not find file instance for "
Steve French26a21b92006-05-31 18:05:34 +0000205 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 }
207 }
208
Steve French7f573562005-08-30 11:32:14 -0700209 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 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 }
Steve French5bafd762006-06-07 00:18:43 +0000264
265 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
266 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
267 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700268 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
269 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000270 else
271 rc = -EIO; /* no NT SMB support fall into legacy open below */
272
Steve Frencha9d02ad2005-08-24 23:06:05 -0700273 if (rc == -EIO) {
274 /* Old server, try legacy style OpenX */
275 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
276 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
277 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
278 & CIFS_MOUNT_MAP_SPECIAL_CHR);
279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000281 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 goto out;
283 }
284 file->private_data =
285 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
286 if (file->private_data == NULL) {
287 rc = -ENOMEM;
288 goto out;
289 }
290 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 write_lock(&GlobalSMBSeslock);
292 list_add(&pCifsFile->tlist, &pTcon->openFileList);
293
294 pCifsInode = CIFS_I(file->f_dentry->d_inode);
295 if (pCifsInode) {
296 rc = cifs_open_inode_helper(inode, file, pCifsInode,
297 pCifsFile, pTcon,
298 &oplock, buf, full_path, xid);
299 } else {
300 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 if (oplock & CIFS_CREATE_ACTION) {
304 /* time to set mode which we can not set earlier due to
305 problems creating new read-only files */
306 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
307 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
308 inode->i_mode,
309 (__u64)-1, (__u64)-1, 0 /* dev */,
Steve French737b7582005-04-28 22:41:06 -0700310 cifs_sb->local_nls,
311 cifs_sb->mnt_cifs_flags &
312 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 } else {
314 /* BB implement via Windows security descriptors eg
315 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
316 -1, -1, local_nls);
317 in the meantime could set r/o dos attribute when
318 perms are eg: mode & 0222 == 0 */
319 }
320 }
321
322out:
323 kfree(buf);
324 kfree(full_path);
325 FreeXid(xid);
326 return rc;
327}
328
Adrian Bunk04187262006-06-30 18:23:04 +0200329/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330/* to server was lost */
331static int cifs_relock_file(struct cifsFileInfo *cifsFile)
332{
333 int rc = 0;
334
335/* BB list all locks open on this file and relock */
336
337 return rc;
338}
339
340static int cifs_reopen_file(struct inode *inode, struct file *file,
341 int can_flush)
342{
343 int rc = -EACCES;
344 int xid, oplock;
345 struct cifs_sb_info *cifs_sb;
346 struct cifsTconInfo *pTcon;
347 struct cifsFileInfo *pCifsFile;
348 struct cifsInodeInfo *pCifsInode;
349 char *full_path = NULL;
350 int desiredAccess;
351 int disposition = FILE_OPEN;
352 __u16 netfid;
353
354 if (inode == NULL)
355 return -EBADF;
356 if (file->private_data) {
357 pCifsFile = (struct cifsFileInfo *)file->private_data;
358 } else
359 return -EBADF;
360
361 xid = GetXid();
362 down(&pCifsFile->fh_sem);
363 if (pCifsFile->invalidHandle == FALSE) {
364 up(&pCifsFile->fh_sem);
365 FreeXid(xid);
366 return 0;
367 }
368
369 if (file->f_dentry == NULL) {
370 up(&pCifsFile->fh_sem);
371 cFYI(1, ("failed file reopen, no valid name if dentry freed"));
372 FreeXid(xid);
373 return -EBADF;
374 }
375 cifs_sb = CIFS_SB(inode->i_sb);
376 pTcon = cifs_sb->tcon;
377/* can not grab rename sem here because various ops, including
378 those that already have the rename sem can end up causing writepage
379 to get called and if the server was down that means we end up here,
380 and we can never tell if the caller already has the rename_sem */
Steve French7f573562005-08-30 11:32:14 -0700381 full_path = build_path_from_dentry(file->f_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 if (full_path == NULL) {
383 up(&pCifsFile->fh_sem);
384 FreeXid(xid);
385 return -ENOMEM;
386 }
387
388 cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
389 inode, file->f_flags,full_path));
390 desiredAccess = cifs_convert_flags(file->f_flags);
391
392 if (oplockEnabled)
393 oplock = REQ_OPLOCK;
394 else
395 oplock = FALSE;
396
397 /* Can not refresh inode by passing in file_info buf to be returned
398 by SMBOpen and then calling get_inode_info with returned buf
399 since file might have write behind data that needs to be flushed
400 and server version of file size can be stale. If we knew for sure
401 that inode was not dirty locally we could do this */
402
403/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
404 if (buf == 0) {
405 up(&pCifsFile->fh_sem);
406 kfree(full_path);
407 FreeXid(xid);
408 return -ENOMEM;
409 } */
410 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
411 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve French737b7582005-04-28 22:41:06 -0700412 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
413 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (rc) {
415 up(&pCifsFile->fh_sem);
Steve French26a21b92006-05-31 18:05:34 +0000416 cFYI(1, ("cifs_open returned 0x%x", rc));
417 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 } else {
419 pCifsFile->netfid = netfid;
420 pCifsFile->invalidHandle = FALSE;
421 up(&pCifsFile->fh_sem);
422 pCifsInode = CIFS_I(inode);
423 if (pCifsInode) {
424 if (can_flush) {
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800425 filemap_write_and_wait(inode->i_mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 /* temporarily disable caching while we
427 go to server to get inode info */
428 pCifsInode->clientCanCacheAll = FALSE;
429 pCifsInode->clientCanCacheRead = FALSE;
430 if (pTcon->ses->capabilities & CAP_UNIX)
431 rc = cifs_get_inode_info_unix(&inode,
432 full_path, inode->i_sb, xid);
433 else
434 rc = cifs_get_inode_info(&inode,
435 full_path, NULL, inode->i_sb,
436 xid);
437 } /* else we are writing out data to server already
438 and could deadlock if we tried to flush data, and
439 since we do not know if we have data that would
440 invalidate the current end of file on the server
441 we can not go to the server to get the new inod
442 info */
443 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
444 pCifsInode->clientCanCacheAll = TRUE;
445 pCifsInode->clientCanCacheRead = TRUE;
446 cFYI(1, ("Exclusive Oplock granted on inode %p",
447 file->f_dentry->d_inode));
448 } else if ((oplock & 0xF) == OPLOCK_READ) {
449 pCifsInode->clientCanCacheRead = TRUE;
450 pCifsInode->clientCanCacheAll = FALSE;
451 } else {
452 pCifsInode->clientCanCacheRead = FALSE;
453 pCifsInode->clientCanCacheAll = FALSE;
454 }
455 cifs_relock_file(pCifsFile);
456 }
457 }
458
459 kfree(full_path);
460 FreeXid(xid);
461 return rc;
462}
463
464int cifs_close(struct inode *inode, struct file *file)
465{
466 int rc = 0;
467 int xid;
468 struct cifs_sb_info *cifs_sb;
469 struct cifsTconInfo *pTcon;
470 struct cifsFileInfo *pSMBFile =
471 (struct cifsFileInfo *)file->private_data;
472
473 xid = GetXid();
474
475 cifs_sb = CIFS_SB(inode->i_sb);
476 pTcon = cifs_sb->tcon;
477 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000478 struct cifsLockInfo *li, *tmp;
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 pSMBFile->closePend = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 if (pTcon) {
482 /* no sense reconnecting to close a file that is
483 already closed */
484 if (pTcon->tidStatus != CifsNeedReconnect) {
Steve French23e7dd72005-10-20 13:44:56 -0700485 int timeout = 2;
486 while((atomic_read(&pSMBFile->wrtPending) != 0)
487 && (timeout < 1000) ) {
488 /* Give write a better chance to get to
489 server ahead of the close. We do not
490 want to add a wait_q here as it would
491 increase the memory utilization as
492 the struct would be in each open file,
493 but this should give enough time to
494 clear the socket */
Steve French4891d532006-11-07 16:31:16 +0000495#ifdef CONFIG_CIFS_DEBUG2
496 cFYI(1,("close delay, write pending"));
497#endif /* DEBUG2 */
Steve French23e7dd72005-10-20 13:44:56 -0700498 msleep(timeout);
499 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000500 }
501 cERROR(1,("close with pending writes"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 rc = CIFSSMBClose(xid, pTcon,
503 pSMBFile->netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
505 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000506
507 /* Delete any outstanding lock records.
508 We'll lose them when the file is closed anyway. */
509 down(&pSMBFile->lock_sem);
510 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
511 list_del(&li->llist);
512 kfree(li);
513 }
514 up(&pSMBFile->lock_sem);
515
Steve Frenchcbe04762005-04-28 22:41:05 -0700516 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 list_del(&pSMBFile->flist);
518 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700519 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 kfree(pSMBFile->search_resume_name);
521 kfree(file->private_data);
522 file->private_data = NULL;
523 } else
524 rc = -EBADF;
525
526 if (list_empty(&(CIFS_I(inode)->openFileList))) {
527 cFYI(1, ("closing last open instance for inode %p", inode));
528 /* if the file is not open we do not know if we can cache info
529 on this inode, much less write behind and read ahead */
530 CIFS_I(inode)->clientCanCacheRead = FALSE;
531 CIFS_I(inode)->clientCanCacheAll = FALSE;
532 }
533 if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
534 rc = CIFS_I(inode)->write_behind_rc;
535 FreeXid(xid);
536 return rc;
537}
538
539int cifs_closedir(struct inode *inode, struct file *file)
540{
541 int rc = 0;
542 int xid;
543 struct cifsFileInfo *pCFileStruct =
544 (struct cifsFileInfo *)file->private_data;
545 char *ptmp;
546
Steve French26a21b92006-05-31 18:05:34 +0000547 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 xid = GetXid();
550
551 if (pCFileStruct) {
552 struct cifsTconInfo *pTcon;
553 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
554
555 pTcon = cifs_sb->tcon;
556
557 cFYI(1, ("Freeing private data in close dir"));
Steve French31ca3bc2005-04-28 22:41:11 -0700558 if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
559 (pCFileStruct->invalidHandle == FALSE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 pCFileStruct->invalidHandle = TRUE;
561 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
562 cFYI(1, ("Closing uncompleted readdir with rc %d",
563 rc));
564 /* not much we can do if it fails anyway, ignore rc */
565 rc = 0;
566 }
567 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
568 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800569 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000571 if(pCFileStruct->srch_inf.smallBuf)
572 cifs_small_buf_release(ptmp);
573 else
574 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
576 ptmp = pCFileStruct->search_resume_name;
577 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800578 cFYI(1, ("closedir free resume name"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 pCFileStruct->search_resume_name = NULL;
580 kfree(ptmp);
581 }
582 kfree(file->private_data);
583 file->private_data = NULL;
584 }
585 /* BB can we lock the filestruct while this is going on? */
586 FreeXid(xid);
587 return rc;
588}
589
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000590static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
591 __u64 offset, __u8 lockType)
592{
593 struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
594 if (li == NULL)
595 return -ENOMEM;
596 li->offset = offset;
597 li->length = len;
598 li->type = lockType;
599 down(&fid->lock_sem);
600 list_add(&li->llist, &fid->llist);
601 up(&fid->lock_sem);
602 return 0;
603}
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
606{
607 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 __u32 numLock = 0;
609 __u32 numUnlock = 0;
610 __u64 length;
611 int wait_flag = FALSE;
612 struct cifs_sb_info *cifs_sb;
613 struct cifsTconInfo *pTcon;
Steve French08547b02006-02-28 22:39:25 +0000614 __u16 netfid;
615 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000616 int posix_locking;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 length = 1 + pfLock->fl_end - pfLock->fl_start;
619 rc = -EACCES;
620 xid = GetXid();
621
622 cFYI(1, ("Lock parm: 0x%x flockflags: "
623 "0x%x flocktype: 0x%x start: %lld end: %lld",
624 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
625 pfLock->fl_end));
626
627 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000628 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000630 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000632 cFYI(1, ("Blocking lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 wait_flag = TRUE;
634 }
635 if (pfLock->fl_flags & FL_ACCESS)
636 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000637 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (pfLock->fl_flags & FL_LEASE)
639 cFYI(1, ("Lease on file - not implemented yet"));
640 if (pfLock->fl_flags &
641 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
642 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
643
644 if (pfLock->fl_type == F_WRLCK) {
645 cFYI(1, ("F_WRLCK "));
646 numLock = 1;
647 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000648 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000650 /* Check if unlock includes more than
651 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000653 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 lockType |= LOCKING_ANDX_SHARED_LOCK;
655 numLock = 1;
656 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000657 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 numLock = 1;
659 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000660 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 lockType |= LOCKING_ANDX_SHARED_LOCK;
662 numLock = 1;
663 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000664 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
667 pTcon = cifs_sb->tcon;
668
669 if (file->private_data == NULL) {
670 FreeXid(xid);
671 return -EBADF;
672 }
Steve French08547b02006-02-28 22:39:25 +0000673 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000675 posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
676 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
Steve French08547b02006-02-28 22:39:25 +0000677
678 /* BB add code here to normalize offset and length to
679 account for negative length which we can not accept over the
680 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (IS_GETLK(cmd)) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000682 if(posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000683 int posix_lock_type;
684 if(lockType & LOCKING_ANDX_SHARED_LOCK)
685 posix_lock_type = CIFS_RDLCK;
686 else
687 posix_lock_type = CIFS_WRLCK;
688 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000689 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000690 posix_lock_type, wait_flag);
691 FreeXid(xid);
692 return rc;
693 }
694
695 /* BB we could chain these into one lock request BB */
696 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
697 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (rc == 0) {
Steve French08547b02006-02-28 22:39:25 +0000699 rc = CIFSSMBLock(xid, pTcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 pfLock->fl_start, 1 /* numUnlock */ ,
701 0 /* numLock */ , lockType,
702 0 /* wait flag */ );
703 pfLock->fl_type = F_UNLCK;
704 if (rc != 0)
705 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000706 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 rc = 0;
708
709 } else {
710 /* if rc == ERR_SHARING_VIOLATION ? */
711 rc = 0; /* do not change lock type to unlock
712 since range in use */
713 }
714
715 FreeXid(xid);
716 return rc;
717 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000718
719 if (!numLock && !numUnlock) {
720 /* if no lock or unlock then nothing
721 to do since we do not know what it is */
722 FreeXid(xid);
723 return -EOPNOTSUPP;
724 }
725
726 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000727 int posix_lock_type;
728 if(lockType & LOCKING_ANDX_SHARED_LOCK)
729 posix_lock_type = CIFS_RDLCK;
730 else
731 posix_lock_type = CIFS_WRLCK;
732
733 if(numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000734 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000735
Steve French08547b02006-02-28 22:39:25 +0000736 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000737 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000738 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000739 } else {
740 struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
741
742 if (numLock) {
743 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
744 0, numLock, lockType, wait_flag);
745
746 if (rc == 0) {
747 /* For Windows locks we must store them. */
748 rc = store_file_lock(fid, length,
749 pfLock->fl_start, lockType);
750 }
751 } else if (numUnlock) {
752 /* For each stored lock that this unlock overlaps
753 completely, unlock it. */
754 int stored_rc = 0;
755 struct cifsLockInfo *li, *tmp;
756
Steve French6b70c952006-09-21 07:35:29 +0000757 rc = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000758 down(&fid->lock_sem);
759 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
760 if (pfLock->fl_start <= li->offset &&
761 length >= li->length) {
762 stored_rc = CIFSSMBLock(xid, pTcon, netfid,
763 li->length, li->offset,
764 1, 0, li->type, FALSE);
765 if (stored_rc)
766 rc = stored_rc;
767
768 list_del(&li->llist);
769 kfree(li);
770 }
771 }
Steve French6b70c952006-09-21 07:35:29 +0000772 up(&fid->lock_sem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000773 }
774 }
775
Steve Frenchd634cc12005-08-26 14:42:59 -0500776 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 posix_lock_file_wait(file, pfLock);
778 FreeXid(xid);
779 return rc;
780}
781
782ssize_t cifs_user_write(struct file *file, const char __user *write_data,
783 size_t write_size, loff_t *poffset)
784{
785 int rc = 0;
786 unsigned int bytes_written = 0;
787 unsigned int total_written;
788 struct cifs_sb_info *cifs_sb;
789 struct cifsTconInfo *pTcon;
790 int xid, long_op;
791 struct cifsFileInfo *open_file;
792
793 if (file->f_dentry == NULL)
794 return -EBADF;
795
796 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
797 if (cifs_sb == NULL)
798 return -EBADF;
799
800 pTcon = cifs_sb->tcon;
801
802 /* cFYI(1,
803 (" write %d bytes to offset %lld of %s", write_size,
804 *poffset, file->f_dentry->d_name.name)); */
805
806 if (file->private_data == NULL)
807 return -EBADF;
808 else
809 open_file = (struct cifsFileInfo *) file->private_data;
810
811 xid = GetXid();
812 if (file->f_dentry->d_inode == NULL) {
813 FreeXid(xid);
814 return -EBADF;
815 }
816
817 if (*poffset > file->f_dentry->d_inode->i_size)
818 long_op = 2; /* writes past end of file can take a long time */
819 else
820 long_op = 1;
821
822 for (total_written = 0; write_size > total_written;
823 total_written += bytes_written) {
824 rc = -EAGAIN;
825 while (rc == -EAGAIN) {
826 if (file->private_data == NULL) {
827 /* file has been closed on us */
828 FreeXid(xid);
829 /* if we have gotten here we have written some data
830 and blocked, and the file has been freed on us while
831 we blocked so return what we managed to write */
832 return total_written;
833 }
834 if (open_file->closePend) {
835 FreeXid(xid);
836 if (total_written)
837 return total_written;
838 else
839 return -EBADF;
840 }
841 if (open_file->invalidHandle) {
842 if ((file->f_dentry == NULL) ||
843 (file->f_dentry->d_inode == NULL)) {
844 FreeXid(xid);
845 return total_written;
846 }
847 /* we could deadlock if we called
848 filemap_fdatawait from here so tell
849 reopen_file not to flush data to server
850 now */
851 rc = cifs_reopen_file(file->f_dentry->d_inode,
852 file, FALSE);
853 if (rc != 0)
854 break;
855 }
856
857 rc = CIFSSMBWrite(xid, pTcon,
858 open_file->netfid,
859 min_t(const int, cifs_sb->wsize,
860 write_size - total_written),
861 *poffset, &bytes_written,
862 NULL, write_data + total_written, long_op);
863 }
864 if (rc || (bytes_written == 0)) {
865 if (total_written)
866 break;
867 else {
868 FreeXid(xid);
869 return rc;
870 }
871 } else
872 *poffset += bytes_written;
873 long_op = FALSE; /* subsequent writes fast -
874 15 seconds is plenty */
875 }
876
Steve Frencha4544342005-08-24 13:59:35 -0700877 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 /* since the write may have blocked check these pointers again */
880 if (file->f_dentry) {
881 if (file->f_dentry->d_inode) {
882 struct inode *inode = file->f_dentry->d_inode;
883 inode->i_ctime = inode->i_mtime =
884 current_fs_time(inode->i_sb);
885 if (total_written > 0) {
886 if (*poffset > file->f_dentry->d_inode->i_size)
887 i_size_write(file->f_dentry->d_inode,
888 *poffset);
889 }
890 mark_inode_dirty_sync(file->f_dentry->d_inode);
891 }
892 }
893 FreeXid(xid);
894 return total_written;
895}
896
897static ssize_t cifs_write(struct file *file, const char *write_data,
898 size_t write_size, loff_t *poffset)
899{
900 int rc = 0;
901 unsigned int bytes_written = 0;
902 unsigned int total_written;
903 struct cifs_sb_info *cifs_sb;
904 struct cifsTconInfo *pTcon;
905 int xid, long_op;
906 struct cifsFileInfo *open_file;
907
908 if (file->f_dentry == NULL)
909 return -EBADF;
910
911 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
912 if (cifs_sb == NULL)
913 return -EBADF;
914
915 pTcon = cifs_sb->tcon;
916
Steve Frenchab2f2182005-09-15 20:44:50 -0700917 cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
918 *poffset, file->f_dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 if (file->private_data == NULL)
921 return -EBADF;
922 else
923 open_file = (struct cifsFileInfo *)file->private_data;
924
925 xid = GetXid();
926 if (file->f_dentry->d_inode == NULL) {
927 FreeXid(xid);
928 return -EBADF;
929 }
930
931 if (*poffset > file->f_dentry->d_inode->i_size)
932 long_op = 2; /* writes past end of file can take a long time */
933 else
934 long_op = 1;
935
936 for (total_written = 0; write_size > total_written;
937 total_written += bytes_written) {
938 rc = -EAGAIN;
939 while (rc == -EAGAIN) {
940 if (file->private_data == NULL) {
941 /* file has been closed on us */
942 FreeXid(xid);
943 /* if we have gotten here we have written some data
944 and blocked, and the file has been freed on us
945 while we blocked so return what we managed to
946 write */
947 return total_written;
948 }
949 if (open_file->closePend) {
950 FreeXid(xid);
951 if (total_written)
952 return total_written;
953 else
954 return -EBADF;
955 }
956 if (open_file->invalidHandle) {
957 if ((file->f_dentry == NULL) ||
958 (file->f_dentry->d_inode == NULL)) {
959 FreeXid(xid);
960 return total_written;
961 }
962 /* we could deadlock if we called
963 filemap_fdatawait from here so tell
964 reopen_file not to flush data to
965 server now */
966 rc = cifs_reopen_file(file->f_dentry->d_inode,
967 file, FALSE);
968 if (rc != 0)
969 break;
970 }
Steve Frenchc01f36a2006-05-30 18:05:10 +0000971 if(experimEnabled || (pTcon->ses->server &&
Steve French08775832006-05-30 18:08:26 +0000972 ((pTcon->ses->server->secMode &
973 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +0000974 == 0))) {
Steve French3e844692005-10-03 13:37:24 -0700975 struct kvec iov[2];
976 unsigned int len;
977
Steve French0ae0efa2005-10-10 10:57:19 -0700978 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -0700979 write_size - total_written);
980 /* iov[0] is reserved for smb header */
981 iov[1].iov_base = (char *)write_data +
982 total_written;
983 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500984 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -0700985 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500986 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -0700987 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500988 } else
Steve French60808232006-04-22 15:53:05 +0000989 rc = CIFSSMBWrite(xid, pTcon,
990 open_file->netfid,
991 min_t(const int, cifs_sb->wsize,
992 write_size - total_written),
993 *poffset, &bytes_written,
994 write_data + total_written,
995 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997 if (rc || (bytes_written == 0)) {
998 if (total_written)
999 break;
1000 else {
1001 FreeXid(xid);
1002 return rc;
1003 }
1004 } else
1005 *poffset += bytes_written;
1006 long_op = FALSE; /* subsequent writes fast -
1007 15 seconds is plenty */
1008 }
1009
Steve Frencha4544342005-08-24 13:59:35 -07001010 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 /* since the write may have blocked check these pointers again */
1013 if (file->f_dentry) {
1014 if (file->f_dentry->d_inode) {
1015 file->f_dentry->d_inode->i_ctime =
1016 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
1017 if (total_written > 0) {
1018 if (*poffset > file->f_dentry->d_inode->i_size)
1019 i_size_write(file->f_dentry->d_inode,
1020 *poffset);
1021 }
1022 mark_inode_dirty_sync(file->f_dentry->d_inode);
1023 }
1024 }
1025 FreeXid(xid);
1026 return total_written;
1027}
1028
Steve Frenchdd99cd82005-10-05 19:32:49 -07001029struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001030{
1031 struct cifsFileInfo *open_file;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001032 int rc;
Steve French6148a742005-10-05 12:23:19 -07001033
Steve French60808232006-04-22 15:53:05 +00001034 /* Having a null inode here (because mapping->host was set to zero by
1035 the VFS or MM) should not happen but we had reports of on oops (due to
1036 it being zero) during stress testcases so we need to check for it */
1037
1038 if(cifs_inode == NULL) {
1039 cERROR(1,("Null inode passed to cifs_writeable_file"));
1040 dump_stack();
1041 return NULL;
1042 }
1043
Steve French6148a742005-10-05 12:23:19 -07001044 read_lock(&GlobalSMBSeslock);
1045 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1046 if (open_file->closePend)
1047 continue;
1048 if (open_file->pfile &&
1049 ((open_file->pfile->f_flags & O_RDWR) ||
1050 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001051 atomic_inc(&open_file->wrtPending);
Steve French6148a742005-10-05 12:23:19 -07001052 read_unlock(&GlobalSMBSeslock);
Steve French0ae0efa2005-10-10 10:57:19 -07001053 if((open_file->invalidHandle) &&
Steve French23e7dd72005-10-20 13:44:56 -07001054 (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
Steve Frenchdd99cd82005-10-05 19:32:49 -07001055 rc = cifs_reopen_file(&cifs_inode->vfs_inode,
Steve French37c0eb42005-10-05 14:50:29 -07001056 open_file->pfile, FALSE);
1057 /* if it fails, try another handle - might be */
1058 /* dangerous to hold up writepages with retry */
1059 if(rc) {
Steve French4a771182005-10-05 15:14:33 -07001060 cFYI(1,("failed on reopen file in wp"));
Steve French37c0eb42005-10-05 14:50:29 -07001061 read_lock(&GlobalSMBSeslock);
Steve French23e7dd72005-10-20 13:44:56 -07001062 /* can not use this handle, no write
1063 pending on this one after all */
1064 atomic_dec
1065 (&open_file->wrtPending);
Steve French37c0eb42005-10-05 14:50:29 -07001066 continue;
1067 }
1068 }
Steve French6148a742005-10-05 12:23:19 -07001069 return open_file;
1070 }
1071 }
1072 read_unlock(&GlobalSMBSeslock);
1073 return NULL;
1074}
1075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1077{
1078 struct address_space *mapping = page->mapping;
1079 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1080 char *write_data;
1081 int rc = -EFAULT;
1082 int bytes_written = 0;
1083 struct cifs_sb_info *cifs_sb;
1084 struct cifsTconInfo *pTcon;
1085 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001086 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 if (!mapping || !mapping->host)
1089 return -EFAULT;
1090
1091 inode = page->mapping->host;
1092 cifs_sb = CIFS_SB(inode->i_sb);
1093 pTcon = cifs_sb->tcon;
1094
1095 offset += (loff_t)from;
1096 write_data = kmap(page);
1097 write_data += from;
1098
1099 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1100 kunmap(page);
1101 return -EIO;
1102 }
1103
1104 /* racing with truncate? */
1105 if (offset > mapping->host->i_size) {
1106 kunmap(page);
1107 return 0; /* don't care */
1108 }
1109
1110 /* check to make sure that we are not extending the file */
1111 if (mapping->host->i_size - offset < (loff_t)to)
1112 to = (unsigned)(mapping->host->i_size - offset);
1113
Steve French6148a742005-10-05 12:23:19 -07001114 open_file = find_writable_file(CIFS_I(mapping->host));
1115 if (open_file) {
1116 bytes_written = cifs_write(open_file->pfile, write_data,
1117 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001118 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001120 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
1121 if ((bytes_written > 0) && (offset)) {
1122 rc = 0;
1123 } else if (bytes_written < 0) {
1124 if (rc != -EBADF)
1125 rc = bytes_written;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
Steve French6148a742005-10-05 12:23:19 -07001127 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 cFYI(1, ("No writeable filehandles for inode"));
1129 rc = -EIO;
1130 }
1131
1132 kunmap(page);
1133 return rc;
1134}
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001137 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Steve French37c0eb42005-10-05 14:50:29 -07001139 struct backing_dev_info *bdi = mapping->backing_dev_info;
1140 unsigned int bytes_to_write;
1141 unsigned int bytes_written;
1142 struct cifs_sb_info *cifs_sb;
1143 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001144 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001145 pgoff_t index;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001146 int range_whole = 0;
Steve French37c0eb42005-10-05 14:50:29 -07001147 struct kvec iov[32];
Steve French84d2f072005-10-12 15:32:05 -07001148 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001149 int n_iov = 0;
1150 pgoff_t next;
1151 int nr_pages;
1152 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001153 struct cifsFileInfo *open_file;
Steve French37c0eb42005-10-05 14:50:29 -07001154 struct page *page;
1155 struct pagevec pvec;
1156 int rc = 0;
1157 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 int xid;
1159
Steve French37c0eb42005-10-05 14:50:29 -07001160 cifs_sb = CIFS_SB(mapping->host->i_sb);
1161
1162 /*
1163 * If wsize is smaller that the page cache size, default to writing
1164 * one page at a time via cifs_writepage
1165 */
1166 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1167 return generic_writepages(mapping, wbc);
1168
Steve French4a771182005-10-05 15:14:33 -07001169 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1170 if(cifs_sb->tcon->ses->server->secMode &
1171 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve French60808232006-04-22 15:53:05 +00001172 if(!experimEnabled)
1173 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001174
Steve French37c0eb42005-10-05 14:50:29 -07001175 /*
1176 * BB: Is this meaningful for a non-block-device file system?
1177 * If it is, we should test it again after we do I/O
1178 */
1179 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1180 wbc->encountered_congestion = 1;
1181 return 0;
1182 }
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 xid = GetXid();
1185
Steve French37c0eb42005-10-05 14:50:29 -07001186 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001187 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001188 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001189 end = -1;
1190 } else {
1191 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1192 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1193 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1194 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001195 scanned = 1;
1196 }
1197retry:
1198 while (!done && (index <= end) &&
1199 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1200 PAGECACHE_TAG_DIRTY,
1201 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1202 int first;
1203 unsigned int i;
1204
Steve French37c0eb42005-10-05 14:50:29 -07001205 first = -1;
1206 next = 0;
1207 n_iov = 0;
1208 bytes_to_write = 0;
1209
1210 for (i = 0; i < nr_pages; i++) {
1211 page = pvec.pages[i];
1212 /*
1213 * At this point we hold neither mapping->tree_lock nor
1214 * lock on the page itself: the page may be truncated or
1215 * invalidated (changing page->mapping to NULL), or even
1216 * swizzled back from swapper_space to tmpfs file
1217 * mapping
1218 */
1219
1220 if (first < 0)
1221 lock_page(page);
1222 else if (TestSetPageLocked(page))
1223 break;
1224
1225 if (unlikely(page->mapping != mapping)) {
1226 unlock_page(page);
1227 break;
1228 }
1229
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001230 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001231 done = 1;
1232 unlock_page(page);
1233 break;
1234 }
1235
1236 if (next && (page->index != next)) {
1237 /* Not next consecutive page */
1238 unlock_page(page);
1239 break;
1240 }
1241
1242 if (wbc->sync_mode != WB_SYNC_NONE)
1243 wait_on_page_writeback(page);
1244
1245 if (PageWriteback(page) ||
1246 !test_clear_page_dirty(page)) {
1247 unlock_page(page);
1248 break;
1249 }
Steve French84d2f072005-10-12 15:32:05 -07001250
1251 if (page_offset(page) >= mapping->host->i_size) {
1252 done = 1;
1253 unlock_page(page);
1254 break;
1255 }
1256
Steve French37c0eb42005-10-05 14:50:29 -07001257 /*
1258 * BB can we get rid of this? pages are held by pvec
1259 */
1260 page_cache_get(page);
1261
Steve French84d2f072005-10-12 15:32:05 -07001262 len = min(mapping->host->i_size - page_offset(page),
1263 (loff_t)PAGE_CACHE_SIZE);
1264
Steve French37c0eb42005-10-05 14:50:29 -07001265 /* reserve iov[0] for the smb header */
1266 n_iov++;
1267 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001268 iov[n_iov].iov_len = len;
1269 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001270
1271 if (first < 0) {
1272 first = i;
1273 offset = page_offset(page);
1274 }
1275 next = page->index + 1;
1276 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1277 break;
1278 }
1279 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001280 /* Search for a writable handle every time we call
1281 * CIFSSMBWrite2. We can't rely on the last handle
1282 * we used to still be valid
1283 */
1284 open_file = find_writable_file(CIFS_I(mapping->host));
1285 if (!open_file) {
1286 cERROR(1, ("No writable handles for inode"));
1287 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001288 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001289 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1290 open_file->netfid,
1291 bytes_to_write, offset,
1292 &bytes_written, iov, n_iov,
1293 1);
1294 atomic_dec(&open_file->wrtPending);
1295 if (rc || bytes_written < bytes_to_write) {
1296 cERROR(1,("Write2 ret %d, written = %d",
1297 rc, bytes_written));
1298 /* BB what if continued retry is
1299 requested via mount flags? */
1300 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001301 } else {
1302 cifs_stats_bytes_written(cifs_sb->tcon,
1303 bytes_written);
1304 }
Steve French37c0eb42005-10-05 14:50:29 -07001305 }
1306 for (i = 0; i < n_iov; i++) {
1307 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001308 /* Should we also set page error on
1309 success rc but too little data written? */
1310 /* BB investigate retry logic on temporary
1311 server crash cases and how recovery works
1312 when page marked as error */
1313 if(rc)
1314 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001315 kunmap(page);
1316 unlock_page(page);
1317 page_cache_release(page);
1318 }
1319 if ((wbc->nr_to_write -= n_iov) <= 0)
1320 done = 1;
1321 index = next;
1322 }
1323 pagevec_release(&pvec);
1324 }
1325 if (!scanned && !done) {
1326 /*
1327 * We hit the last page and there is more work to be done: wrap
1328 * back to the start of the file
1329 */
1330 scanned = 1;
1331 index = 0;
1332 goto retry;
1333 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001334 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001335 mapping->writeback_index = index;
1336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 FreeXid(xid);
Steve French37c0eb42005-10-05 14:50:29 -07001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 return rc;
1340}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
1342static int cifs_writepage(struct page* page, struct writeback_control *wbc)
1343{
1344 int rc = -EFAULT;
1345 int xid;
1346
1347 xid = GetXid();
1348/* BB add check for wbc flags */
1349 page_cache_get(page);
1350 if (!PageUptodate(page)) {
1351 cFYI(1, ("ppw - page not up to date"));
1352 }
1353
1354 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1355 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1356 unlock_page(page);
1357 page_cache_release(page);
1358 FreeXid(xid);
1359 return rc;
1360}
1361
1362static int cifs_commit_write(struct file *file, struct page *page,
1363 unsigned offset, unsigned to)
1364{
1365 int xid;
1366 int rc = 0;
1367 struct inode *inode = page->mapping->host;
1368 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1369 char *page_data;
1370
1371 xid = GetXid();
1372 cFYI(1, ("commit write for page %p up to position %lld for %d",
1373 page, position, to));
1374 if (position > inode->i_size) {
1375 i_size_write(inode, position);
1376 /* if (file->private_data == NULL) {
1377 rc = -EBADF;
1378 } else {
1379 open_file = (struct cifsFileInfo *)file->private_data;
1380 cifs_sb = CIFS_SB(inode->i_sb);
1381 rc = -EAGAIN;
1382 while (rc == -EAGAIN) {
1383 if ((open_file->invalidHandle) &&
1384 (!open_file->closePend)) {
1385 rc = cifs_reopen_file(
1386 file->f_dentry->d_inode, file);
1387 if (rc != 0)
1388 break;
1389 }
1390 if (!open_file->closePend) {
1391 rc = CIFSSMBSetFileSize(xid,
1392 cifs_sb->tcon, position,
1393 open_file->netfid,
1394 open_file->pid, FALSE);
1395 } else {
1396 rc = -EBADF;
1397 break;
1398 }
1399 }
1400 cFYI(1, (" SetEOF (commit write) rc = %d", rc));
1401 } */
1402 }
1403 if (!PageUptodate(page)) {
1404 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
1405 /* can not rely on (or let) writepage write this data */
1406 if (to < offset) {
1407 cFYI(1, ("Illegal offsets, can not copy from %d to %d",
1408 offset, to));
1409 FreeXid(xid);
1410 return rc;
1411 }
1412 /* this is probably better than directly calling
1413 partialpage_write since in this function the file handle is
1414 known which we might as well leverage */
1415 /* BB check if anything else missing out of ppw
1416 such as updating last write time */
1417 page_data = kmap(page);
1418 rc = cifs_write(file, page_data + offset, to-offset,
1419 &position);
1420 if (rc > 0)
1421 rc = 0;
1422 /* else if (rc < 0) should we set writebehind rc? */
1423 kunmap(page);
1424 } else {
1425 set_page_dirty(page);
1426 }
1427
1428 FreeXid(xid);
1429 return rc;
1430}
1431
1432int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1433{
1434 int xid;
1435 int rc = 0;
1436 struct inode *inode = file->f_dentry->d_inode;
1437
1438 xid = GetXid();
1439
Steve French26a21b92006-05-31 18:05:34 +00001440 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 dentry->d_name.name, datasync));
1442
1443 rc = filemap_fdatawrite(inode->i_mapping);
1444 if (rc == 0)
1445 CIFS_I(inode)->write_behind_rc = 0;
1446 FreeXid(xid);
1447 return rc;
1448}
1449
NeilBrown3978d712006-03-26 01:37:17 -08001450/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 struct address_space *mapping;
1453 struct inode *inode;
1454 unsigned long index = page->index;
1455 unsigned int rpages = 0;
1456 int rc = 0;
1457
1458 cFYI(1, ("sync page %p",page));
1459 mapping = page->mapping;
1460 if (!mapping)
1461 return 0;
1462 inode = mapping->host;
1463 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001464 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466/* fill in rpages then
1467 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1468
Steve French26a21b92006-05-31 18:05:34 +00001469/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
NeilBrown3978d712006-03-26 01:37:17 -08001471#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (rc < 0)
1473 return rc;
1474 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001475#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476} */
1477
1478/*
1479 * As file closes, flush all cached write data for this inode checking
1480 * for write behind errors.
1481 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001482int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 struct inode * inode = file->f_dentry->d_inode;
1485 int rc = 0;
1486
1487 /* Rather than do the steps manually:
1488 lock the inode for writing
1489 loop through pages looking for write behind data (dirty pages)
1490 coalesce into contiguous 16K (or smaller) chunks to write to server
1491 send to server (prefer in parallel)
1492 deal with writebehind errors
1493 unlock inode for writing
1494 filemapfdatawrite appears easier for the time being */
1495
1496 rc = filemap_fdatawrite(inode->i_mapping);
1497 if (!rc) /* reset wb rc if we were able to write out dirty pages */
1498 CIFS_I(inode)->write_behind_rc = 0;
1499
1500 cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
1501
1502 return rc;
1503}
1504
1505ssize_t cifs_user_read(struct file *file, char __user *read_data,
1506 size_t read_size, loff_t *poffset)
1507{
1508 int rc = -EACCES;
1509 unsigned int bytes_read = 0;
1510 unsigned int total_read = 0;
1511 unsigned int current_read_size;
1512 struct cifs_sb_info *cifs_sb;
1513 struct cifsTconInfo *pTcon;
1514 int xid;
1515 struct cifsFileInfo *open_file;
1516 char *smb_read_data;
1517 char __user *current_offset;
1518 struct smb_com_read_rsp *pSMBr;
1519
1520 xid = GetXid();
1521 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1522 pTcon = cifs_sb->tcon;
1523
1524 if (file->private_data == NULL) {
1525 FreeXid(xid);
1526 return -EBADF;
1527 }
1528 open_file = (struct cifsFileInfo *)file->private_data;
1529
1530 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
1531 cFYI(1, ("attempting read on write only file instance"));
1532 }
1533 for (total_read = 0, current_offset = read_data;
1534 read_size > total_read;
1535 total_read += bytes_read, current_offset += bytes_read) {
1536 current_read_size = min_t(const int, read_size - total_read,
1537 cifs_sb->rsize);
1538 rc = -EAGAIN;
1539 smb_read_data = NULL;
1540 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001541 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 if ((open_file->invalidHandle) &&
1543 (!open_file->closePend)) {
1544 rc = cifs_reopen_file(file->f_dentry->d_inode,
1545 file, TRUE);
1546 if (rc != 0)
1547 break;
1548 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001549 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001550 open_file->netfid,
1551 current_read_size, *poffset,
1552 &bytes_read, &smb_read_data,
1553 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001556 if (copy_to_user(current_offset,
1557 smb_read_data +
1558 4 /* RFC1001 length field */ +
1559 le16_to_cpu(pSMBr->DataOffset),
1560 bytes_read)) {
1561 rc = -EFAULT;
1562 }
1563
Steve Frenchec637e32005-12-12 20:53:18 -08001564 if(buf_type == CIFS_SMALL_BUFFER)
1565 cifs_small_buf_release(smb_read_data);
1566 else if(buf_type == CIFS_LARGE_BUFFER)
1567 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 smb_read_data = NULL;
1569 }
1570 }
1571 if (rc || (bytes_read == 0)) {
1572 if (total_read) {
1573 break;
1574 } else {
1575 FreeXid(xid);
1576 return rc;
1577 }
1578 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001579 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 *poffset += bytes_read;
1581 }
1582 }
1583 FreeXid(xid);
1584 return total_read;
1585}
1586
1587
1588static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1589 loff_t *poffset)
1590{
1591 int rc = -EACCES;
1592 unsigned int bytes_read = 0;
1593 unsigned int total_read;
1594 unsigned int current_read_size;
1595 struct cifs_sb_info *cifs_sb;
1596 struct cifsTconInfo *pTcon;
1597 int xid;
1598 char *current_offset;
1599 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001600 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 xid = GetXid();
1603 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1604 pTcon = cifs_sb->tcon;
1605
1606 if (file->private_data == NULL) {
1607 FreeXid(xid);
1608 return -EBADF;
1609 }
1610 open_file = (struct cifsFileInfo *)file->private_data;
1611
1612 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1613 cFYI(1, ("attempting read on write only file instance"));
1614
1615 for (total_read = 0, current_offset = read_data;
1616 read_size > total_read;
1617 total_read += bytes_read, current_offset += bytes_read) {
1618 current_read_size = min_t(const int, read_size - total_read,
1619 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001620 /* For windows me and 9x we do not want to request more
1621 than it negotiated since it will refuse the read then */
1622 if((pTcon->ses) &&
1623 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1624 current_read_size = min_t(const int, current_read_size,
1625 pTcon->ses->server->maxBuf - 128);
1626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 rc = -EAGAIN;
1628 while (rc == -EAGAIN) {
1629 if ((open_file->invalidHandle) &&
1630 (!open_file->closePend)) {
1631 rc = cifs_reopen_file(file->f_dentry->d_inode,
1632 file, TRUE);
1633 if (rc != 0)
1634 break;
1635 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001636 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001637 open_file->netfid,
1638 current_read_size, *poffset,
1639 &bytes_read, &current_offset,
1640 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 }
1642 if (rc || (bytes_read == 0)) {
1643 if (total_read) {
1644 break;
1645 } else {
1646 FreeXid(xid);
1647 return rc;
1648 }
1649 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001650 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 *poffset += bytes_read;
1652 }
1653 }
1654 FreeXid(xid);
1655 return total_read;
1656}
1657
1658int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1659{
1660 struct dentry *dentry = file->f_dentry;
1661 int rc, xid;
1662
1663 xid = GetXid();
1664 rc = cifs_revalidate(dentry);
1665 if (rc) {
1666 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1667 FreeXid(xid);
1668 return rc;
1669 }
1670 rc = generic_file_mmap(file, vma);
1671 FreeXid(xid);
1672 return rc;
1673}
1674
1675
1676static void cifs_copy_cache_pages(struct address_space *mapping,
1677 struct list_head *pages, int bytes_read, char *data,
1678 struct pagevec *plru_pvec)
1679{
1680 struct page *page;
1681 char *target;
1682
1683 while (bytes_read > 0) {
1684 if (list_empty(pages))
1685 break;
1686
1687 page = list_entry(pages->prev, struct page, lru);
1688 list_del(&page->lru);
1689
1690 if (add_to_page_cache(page, mapping, page->index,
1691 GFP_KERNEL)) {
1692 page_cache_release(page);
1693 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001694 data += PAGE_CACHE_SIZE;
1695 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 continue;
1697 }
1698
1699 target = kmap_atomic(page,KM_USER0);
1700
1701 if (PAGE_CACHE_SIZE > bytes_read) {
1702 memcpy(target, data, bytes_read);
1703 /* zero the tail end of this partial page */
1704 memset(target + bytes_read, 0,
1705 PAGE_CACHE_SIZE - bytes_read);
1706 bytes_read = 0;
1707 } else {
1708 memcpy(target, data, PAGE_CACHE_SIZE);
1709 bytes_read -= PAGE_CACHE_SIZE;
1710 }
1711 kunmap_atomic(target, KM_USER0);
1712
1713 flush_dcache_page(page);
1714 SetPageUptodate(page);
1715 unlock_page(page);
1716 if (!pagevec_add(plru_pvec, page))
1717 __pagevec_lru_add(plru_pvec);
1718 data += PAGE_CACHE_SIZE;
1719 }
1720 return;
1721}
1722
1723static int cifs_readpages(struct file *file, struct address_space *mapping,
1724 struct list_head *page_list, unsigned num_pages)
1725{
1726 int rc = -EACCES;
1727 int xid;
1728 loff_t offset;
1729 struct page *page;
1730 struct cifs_sb_info *cifs_sb;
1731 struct cifsTconInfo *pTcon;
1732 int bytes_read = 0;
1733 unsigned int read_size,i;
1734 char *smb_read_data = NULL;
1735 struct smb_com_read_rsp *pSMBr;
1736 struct pagevec lru_pvec;
1737 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001738 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 xid = GetXid();
1741 if (file->private_data == NULL) {
1742 FreeXid(xid);
1743 return -EBADF;
1744 }
1745 open_file = (struct cifsFileInfo *)file->private_data;
1746 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1747 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 pagevec_init(&lru_pvec, 0);
1750
1751 for (i = 0; i < num_pages; ) {
1752 unsigned contig_pages;
1753 struct page *tmp_page;
1754 unsigned long expected_index;
1755
1756 if (list_empty(page_list))
1757 break;
1758
1759 page = list_entry(page_list->prev, struct page, lru);
1760 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1761
1762 /* count adjacent pages that we will read into */
1763 contig_pages = 0;
1764 expected_index =
1765 list_entry(page_list->prev, struct page, lru)->index;
1766 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1767 if (tmp_page->index == expected_index) {
1768 contig_pages++;
1769 expected_index++;
1770 } else
1771 break;
1772 }
1773 if (contig_pages + i > num_pages)
1774 contig_pages = num_pages - i;
1775
1776 /* for reads over a certain size could initiate async
1777 read ahead */
1778
1779 read_size = contig_pages * PAGE_CACHE_SIZE;
1780 /* Read size needs to be in multiples of one page */
1781 read_size = min_t(const unsigned int, read_size,
1782 cifs_sb->rsize & PAGE_CACHE_MASK);
1783
1784 rc = -EAGAIN;
1785 while (rc == -EAGAIN) {
1786 if ((open_file->invalidHandle) &&
1787 (!open_file->closePend)) {
1788 rc = cifs_reopen_file(file->f_dentry->d_inode,
1789 file, TRUE);
1790 if (rc != 0)
1791 break;
1792 }
1793
Steve Frenchbfa0d752005-08-31 21:50:37 -07001794 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001795 open_file->netfid,
1796 read_size, offset,
1797 &bytes_read, &smb_read_data,
1798 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001799 /* BB more RC checks ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 if (rc== -EAGAIN) {
1801 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001802 if(buf_type == CIFS_SMALL_BUFFER)
1803 cifs_small_buf_release(smb_read_data);
1804 else if(buf_type == CIFS_LARGE_BUFFER)
1805 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 smb_read_data = NULL;
1807 }
1808 }
1809 }
1810 if ((rc < 0) || (smb_read_data == NULL)) {
1811 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 break;
1813 } else if (bytes_read > 0) {
1814 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1815 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1816 smb_read_data + 4 /* RFC1001 hdr */ +
1817 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1818
1819 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001820 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1822 i++; /* account for partial page */
1823
1824 /* server copy of file can have smaller size
1825 than client */
1826 /* BB do we need to verify this common case ?
1827 this case is ok - if we are at server EOF
1828 we will hit it on next read */
1829
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001830 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 }
1832 } else {
1833 cFYI(1, ("No bytes read (%d) at offset %lld . "
1834 "Cleaning remaining pages from readahead list",
1835 bytes_read, offset));
1836 /* BB turn off caching and do new lookup on
1837 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 break;
1839 }
1840 if (smb_read_data) {
Steve Frenchec637e32005-12-12 20:53:18 -08001841 if(buf_type == CIFS_SMALL_BUFFER)
1842 cifs_small_buf_release(smb_read_data);
1843 else if(buf_type == CIFS_LARGE_BUFFER)
1844 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 smb_read_data = NULL;
1846 }
1847 bytes_read = 0;
1848 }
1849
1850 pagevec_lru_add(&lru_pvec);
1851
1852/* need to free smb_read_data buf before exit */
1853 if (smb_read_data) {
Steve French47c886b2006-01-18 14:20:39 -08001854 if(buf_type == CIFS_SMALL_BUFFER)
1855 cifs_small_buf_release(smb_read_data);
1856 else if(buf_type == CIFS_LARGE_BUFFER)
1857 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 smb_read_data = NULL;
1859 }
1860
1861 FreeXid(xid);
1862 return rc;
1863}
1864
1865static int cifs_readpage_worker(struct file *file, struct page *page,
1866 loff_t *poffset)
1867{
1868 char *read_data;
1869 int rc;
1870
1871 page_cache_get(page);
1872 read_data = kmap(page);
1873 /* for reads over a certain size could initiate async read ahead */
1874
1875 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
1876
1877 if (rc < 0)
1878 goto io_error;
1879 else
Steve French26a21b92006-05-31 18:05:34 +00001880 cFYI(1, ("Bytes read %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 file->f_dentry->d_inode->i_atime =
1883 current_fs_time(file->f_dentry->d_inode->i_sb);
1884
1885 if (PAGE_CACHE_SIZE > rc)
1886 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1887
1888 flush_dcache_page(page);
1889 SetPageUptodate(page);
1890 rc = 0;
1891
1892io_error:
1893 kunmap(page);
1894 page_cache_release(page);
1895 return rc;
1896}
1897
1898static int cifs_readpage(struct file *file, struct page *page)
1899{
1900 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1901 int rc = -EACCES;
1902 int xid;
1903
1904 xid = GetXid();
1905
1906 if (file->private_data == NULL) {
1907 FreeXid(xid);
1908 return -EBADF;
1909 }
1910
1911 cFYI(1, ("readpage %p at offset %d 0x%x\n",
1912 page, (int)offset, (int)offset));
1913
1914 rc = cifs_readpage_worker(file, page, &offset);
1915
1916 unlock_page(page);
1917
1918 FreeXid(xid);
1919 return rc;
1920}
1921
1922/* We do not want to update the file size from server for inodes
1923 open for write - to avoid races with writepage extending
1924 the file - in the future we could consider allowing
1925 refreshing the inode only on increases in the file size
1926 but this is tricky to do without racing with writebehind
1927 page caching in the current Linux kernel design */
1928int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1929{
Steve French23e7dd72005-10-20 13:44:56 -07001930 struct cifsFileInfo *open_file = NULL;
1931
1932 if (cifsInode)
1933 open_file = find_writable_file(cifsInode);
1934
1935 if(open_file) {
Steve Frenchc32a0b62006-01-12 14:41:28 -08001936 struct cifs_sb_info *cifs_sb;
1937
Steve French23e7dd72005-10-20 13:44:56 -07001938 /* there is not actually a write pending so let
1939 this handle go free and allow it to
1940 be closable if needed */
1941 atomic_dec(&open_file->wrtPending);
Steve Frenchc32a0b62006-01-12 14:41:28 -08001942
1943 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
1944 if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
1945 /* since no page cache to corrupt on directio
1946 we can change size safely */
1947 return 1;
1948 }
1949
Steve French6148a742005-10-05 12:23:19 -07001950 return 0;
Steve French23e7dd72005-10-20 13:44:56 -07001951 } else
Steve French6148a742005-10-05 12:23:19 -07001952 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955static int cifs_prepare_write(struct file *file, struct page *page,
1956 unsigned from, unsigned to)
1957{
1958 int rc = 0;
1959 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1960 cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
1961 if (!PageUptodate(page)) {
1962 /* if (to - from != PAGE_CACHE_SIZE) {
1963 void *kaddr = kmap_atomic(page, KM_USER0);
1964 memset(kaddr, 0, from);
1965 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1966 flush_dcache_page(page);
1967 kunmap_atomic(kaddr, KM_USER0);
1968 } */
1969 /* If we are writing a full page it will be up to date,
1970 no need to read from the server */
1971 if ((to == PAGE_CACHE_SIZE) && (from == 0))
1972 SetPageUptodate(page);
1973
1974 /* might as well read a page, it is fast enough */
1975 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
1976 rc = cifs_readpage_worker(file, page, &offset);
1977 } else {
1978 /* should we try using another file handle if there is one -
1979 how would we lock it to prevent close of that handle
1980 racing with this read?
1981 In any case this will be written out by commit_write */
1982 }
1983 }
1984
1985 /* BB should we pass any errors back?
1986 e.g. if we do not have read access to the file */
1987 return 0;
1988}
1989
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07001990const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 .readpage = cifs_readpage,
1992 .readpages = cifs_readpages,
1993 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07001994 .writepages = cifs_writepages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 .prepare_write = cifs_prepare_write,
1996 .commit_write = cifs_commit_write,
1997 .set_page_dirty = __set_page_dirty_nobuffers,
1998 /* .sync_page = cifs_sync_page, */
1999 /* .direct_IO = */
2000};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002001
2002/*
2003 * cifs_readpages requires the server to support a buffer large enough to
2004 * contain the header plus one complete page of data. Otherwise, we need
2005 * to leave cifs_readpages out of the address space operations.
2006 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002007const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002008 .readpage = cifs_readpage,
2009 .writepage = cifs_writepage,
2010 .writepages = cifs_writepages,
2011 .prepare_write = cifs_prepare_write,
2012 .commit_write = cifs_commit_write,
2013 .set_page_dirty = __set_page_dirty_nobuffers,
2014 /* .sync_page = cifs_sync_page, */
2015 /* .direct_IO = */
2016};