blob: 6603cb4024fbde23f014360a7f28dd865d5d995d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
6 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.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;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000048 private_data->pid = current->tgid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 init_MUTEX(&private_data->fh_sem);
Roland Dreier796e5662007-05-03 04:33:45 +000050 mutex_init(&private_data->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +000051 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;
Steve French4b18f2a2008-04-29 00:06:05 +000054 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 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +000060 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
Jeff Laytone10f7b52008-05-14 10:21:33 -070078 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
80 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000081}
Jeff Laytone10f7b52008-05-14 10:21:33 -070082
Steve French7fc8f4e2009-02-23 20:43:11 +000083static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
84{
85 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070086
Steve French7fc8f4e2009-02-23 20:43:11 +000087 if ((flags & O_ACCMODE) == O_RDONLY)
88 posix_flags = FMODE_READ;
89 else if ((flags & O_ACCMODE) == O_WRONLY)
90 posix_flags = FMODE_WRITE;
91 else if ((flags & O_ACCMODE) == O_RDWR) {
92 /* GENERIC_ALL is too much permission to request
93 can cause unnecessary access denied on create */
94 /* return GENERIC_ALL; */
95 posix_flags = FMODE_READ | FMODE_WRITE;
96 }
97 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
98 reopening a file. They had their effect on the original open */
99 if (flags & O_APPEND)
100 posix_flags |= (fmode_t)O_APPEND;
101 if (flags & O_SYNC)
102 posix_flags |= (fmode_t)O_SYNC;
103 if (flags & O_DIRECTORY)
104 posix_flags |= (fmode_t)O_DIRECTORY;
105 if (flags & O_NOFOLLOW)
106 posix_flags |= (fmode_t)O_NOFOLLOW;
107 if (flags & O_DIRECT)
108 posix_flags |= (fmode_t)O_DIRECT;
109
110 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113static inline int cifs_get_disposition(unsigned int flags)
114{
115 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
116 return FILE_CREATE;
117 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
118 return FILE_OVERWRITE_IF;
119 else if ((flags & O_CREAT) == O_CREAT)
120 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000121 else if ((flags & O_TRUNC) == O_TRUNC)
122 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 else
124 return FILE_OPEN;
125}
126
127/* all arguments to this function must be checked for validity in caller */
128static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
129 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
130 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
131 char *full_path, int xid)
132{
133 struct timespec temp;
134 int rc;
135
136 /* want handles we can use to read with first
137 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400138 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000140 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 &pCifsInode->openFileList);
142 } else {
143 list_add(&pCifsFile->flist,
144 &pCifsInode->openFileList);
145 }
146 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (pCifsInode->clientCanCacheRead) {
148 /* we have the inode open somewhere else
149 no need to discard cache data */
150 goto client_can_cache;
151 }
152
153 /* BB need same check in cifs_create too? */
154 /* if not oplocked, invalidate inode pages if mtime or file
155 size changed */
156 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800157 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
158 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 (loff_t)le64_to_cpu(buf->EndOfFile))) {
160 cFYI(1, ("inode unchanged on server"));
161 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800162 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 /* BB no need to lock inode until after invalidate
164 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000165 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
166 if (rc != 0)
167 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169 cFYI(1, ("invalidating remote inode since open detected it "
170 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800171 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
173
174client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000175 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800176 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 full_path, inode->i_sb, xid);
178 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800179 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000180 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000183 pCifsInode->clientCanCacheAll = true;
184 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800186 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000188 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 return rc;
191}
192
193int cifs_open(struct inode *inode, struct file *file)
194{
195 int rc = -EACCES;
196 int xid, oplock;
197 struct cifs_sb_info *cifs_sb;
198 struct cifsTconInfo *pTcon;
199 struct cifsFileInfo *pCifsFile;
200 struct cifsInodeInfo *pCifsInode;
201 struct list_head *tmp;
202 char *full_path = NULL;
203 int desiredAccess;
204 int disposition;
205 __u16 netfid;
206 FILE_ALL_INFO *buf = NULL;
207
208 xid = GetXid();
209
210 cifs_sb = CIFS_SB(inode->i_sb);
211 pTcon = cifs_sb->tcon;
212
213 if (file->f_flags & O_CREAT) {
214 /* search inode for this file and fill in file->private_data */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800215 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 read_lock(&GlobalSMBSeslock);
217 list_for_each(tmp, &pCifsInode->openFileList) {
218 pCifsFile = list_entry(tmp, struct cifsFileInfo,
219 flist);
220 if ((pCifsFile->pfile == NULL) &&
221 (pCifsFile->pid == current->tgid)) {
222 /* mode set in cifs_create */
223
224 /* needed for writepage */
225 pCifsFile->pfile = file;
Steve French50c2f752007-07-13 00:33:32 +0000226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 file->private_data = pCifsFile;
228 break;
229 }
230 }
231 read_unlock(&GlobalSMBSeslock);
232 if (file->private_data != NULL) {
233 rc = 0;
234 FreeXid(xid);
235 return rc;
236 } else {
237 if (file->f_flags & O_EXCL)
238 cERROR(1, ("could not find file instance for "
Steve French26a21b92006-05-31 18:05:34 +0000239 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 }
241 }
242
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800243 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 if (full_path == NULL) {
245 FreeXid(xid);
246 return -ENOMEM;
247 }
248
Steve French7521a3c2007-07-11 18:30:34 +0000249 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 inode, file->f_flags, full_path));
251 desiredAccess = cifs_convert_flags(file->f_flags);
252
253/*********************************************************************
254 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000255 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000257 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 * O_CREAT FILE_OPEN_IF
259 * O_CREAT | O_EXCL FILE_CREATE
260 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
261 * O_TRUNC FILE_OVERWRITE
262 * none of the above FILE_OPEN
263 *
264 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000265 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 * O_CREAT | O_TRUNC is similar but truncates the existing
267 * file rather than creating a new file as FILE_SUPERSEDE does
268 * (which uses the attributes / metadata passed in on open call)
269 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000270 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 *? and the read write flags match reasonably. O_LARGEFILE
272 *? is irrelevant because largefile support is always used
273 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
274 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
275 *********************************************************************/
276
277 disposition = cifs_get_disposition(file->f_flags);
278
279 if (oplockEnabled)
280 oplock = REQ_OPLOCK;
281 else
Steve French4b18f2a2008-04-29 00:06:05 +0000282 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 /* BB pass O_SYNC flag through on file attributes .. BB */
285
286 /* Also refresh inode by passing in file_info buf returned by SMBOpen
287 and calling get_inode_info with returned buf (at least helps
288 non-Unix server case) */
289
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000290 /* BB we can not do this if this is the second open of a file
291 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
293 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
294 if (!buf) {
295 rc = -ENOMEM;
296 goto out;
297 }
Steve French5bafd762006-06-07 00:18:43 +0000298
299 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000301 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700302 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
303 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000304 else
305 rc = -EIO; /* no NT SMB support fall into legacy open below */
306
Steve Frencha9d02ad2005-08-24 23:06:05 -0700307 if (rc == -EIO) {
308 /* Old server, try legacy style OpenX */
309 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
310 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
311 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
312 & CIFS_MOUNT_MAP_SPECIAL_CHR);
313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000315 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 goto out;
317 }
318 file->private_data =
319 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
320 if (file->private_data == NULL) {
321 rc = -ENOMEM;
322 goto out;
323 }
324 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 write_lock(&GlobalSMBSeslock);
326 list_add(&pCifsFile->tlist, &pTcon->openFileList);
327
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800328 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 if (pCifsInode) {
330 rc = cifs_open_inode_helper(inode, file, pCifsInode,
331 pCifsFile, pTcon,
332 &oplock, buf, full_path, xid);
333 } else {
334 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000337 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 /* time to set mode which we can not set earlier due to
339 problems creating new read-only files */
Steve Frenchc18c8422007-07-18 23:21:09 +0000340 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400341 struct cifs_unix_set_info_args args = {
342 .mode = inode->i_mode,
343 .uid = NO_CHANGE_64,
344 .gid = NO_CHANGE_64,
345 .ctime = NO_CHANGE_64,
346 .atime = NO_CHANGE_64,
347 .mtime = NO_CHANGE_64,
348 .device = 0,
349 };
350 CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
Steve French737b7582005-04-28 22:41:06 -0700351 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000352 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700353 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
355 }
356
357out:
358 kfree(buf);
359 kfree(full_path);
360 FreeXid(xid);
361 return rc;
362}
363
Adrian Bunk04187262006-06-30 18:23:04 +0200364/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365/* to server was lost */
366static int cifs_relock_file(struct cifsFileInfo *cifsFile)
367{
368 int rc = 0;
369
370/* BB list all locks open on this file and relock */
371
372 return rc;
373}
374
Steve French4b18f2a2008-04-29 00:06:05 +0000375static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 int rc = -EACCES;
378 int xid, oplock;
379 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000380 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 struct cifsFileInfo *pCifsFile;
382 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000383 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 char *full_path = NULL;
385 int desiredAccess;
386 int disposition = FILE_OPEN;
387 __u16 netfid;
388
Steve Frenchad7a2922008-02-07 23:25:02 +0000389 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000391 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return -EBADF;
393
394 xid = GetXid();
395 down(&pCifsFile->fh_sem);
Steve French4b18f2a2008-04-29 00:06:05 +0000396 if (!pCifsFile->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 up(&pCifsFile->fh_sem);
398 FreeXid(xid);
399 return 0;
400 }
401
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800402 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000403 cERROR(1, ("no valid name if dentry freed"));
404 dump_stack();
405 rc = -EBADF;
406 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 }
Steve French3a9f4622007-04-04 17:10:24 +0000408
409 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000410 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000411 cERROR(1, ("inode not valid"));
412 dump_stack();
413 rc = -EBADF;
414 goto reopen_error_exit;
415 }
Steve French50c2f752007-07-13 00:33:32 +0000416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000418 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420/* can not grab rename sem here because various ops, including
421 those that already have the rename sem can end up causing writepage
422 to get called and if the server was down that means we end up here,
423 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800424 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000426 rc = -ENOMEM;
427reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 up(&pCifsFile->fh_sem);
429 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000430 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 }
432
Steve French3a9f4622007-04-04 17:10:24 +0000433 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000434 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (oplockEnabled)
437 oplock = REQ_OPLOCK;
438 else
Steve French4b18f2a2008-04-29 00:06:05 +0000439 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Steve French7fc8f4e2009-02-23 20:43:11 +0000441 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
442 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
443 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
444 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
445 /* can not refresh inode info since size could be stale */
446 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
447 cifs_sb->mnt_file_mode /* ignored */,
448 oflags, &oplock, &netfid, xid);
449 if (rc == 0) {
450 cFYI(1, ("posix reopen succeeded"));
451 goto reopen_success;
452 }
453 /* fallthrough to retry open the old way on errors, especially
454 in the reconnect path it is important to retry hard */
455 }
456
457 desiredAccess = cifs_convert_flags(file->f_flags);
458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000460 by SMBOpen and then calling get_inode_info with returned buf
461 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 and server version of file size can be stale. If we knew for sure
463 that inode was not dirty locally we could do this */
464
Steve French7fc8f4e2009-02-23 20:43:11 +0000465 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000467 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700468 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (rc) {
470 up(&pCifsFile->fh_sem);
Steve French26a21b92006-05-31 18:05:34 +0000471 cFYI(1, ("cifs_open returned 0x%x", rc));
472 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000474reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000476 pCifsFile->invalidHandle = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 up(&pCifsFile->fh_sem);
478 pCifsInode = CIFS_I(inode);
479 if (pCifsInode) {
480 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000481 rc = filemap_write_and_wait(inode->i_mapping);
482 if (rc != 0)
483 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 /* temporarily disable caching while we
485 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000486 pCifsInode->clientCanCacheAll = false;
487 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000488 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 rc = cifs_get_inode_info_unix(&inode,
490 full_path, inode->i_sb, xid);
491 else
492 rc = cifs_get_inode_info(&inode,
493 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000494 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 } /* else we are writing out data to server already
496 and could deadlock if we tried to flush data, and
497 since we do not know if we have data that would
498 invalidate the current end of file on the server
499 we can not go to the server to get the new inod
500 info */
501 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000502 pCifsInode->clientCanCacheAll = true;
503 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800505 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000507 pCifsInode->clientCanCacheRead = true;
508 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000510 pCifsInode->clientCanCacheRead = false;
511 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513 cifs_relock_file(pCifsFile);
514 }
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 kfree(full_path);
517 FreeXid(xid);
518 return rc;
519}
520
521int cifs_close(struct inode *inode, struct file *file)
522{
523 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000524 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 struct cifs_sb_info *cifs_sb;
526 struct cifsTconInfo *pTcon;
527 struct cifsFileInfo *pSMBFile =
528 (struct cifsFileInfo *)file->private_data;
529
530 xid = GetXid();
531
532 cifs_sb = CIFS_SB(inode->i_sb);
533 pTcon = cifs_sb->tcon;
534 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000535 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000536 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000537 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (pTcon) {
539 /* no sense reconnecting to close a file that is
540 already closed */
Steve French3b795212008-11-13 19:45:32 +0000541 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000542 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000543 timeout = 2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000544 while ((atomic_read(&pSMBFile->wrtPending) != 0)
Steve French15745322007-09-07 22:23:48 +0000545 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700546 /* Give write a better chance to get to
547 server ahead of the close. We do not
548 want to add a wait_q here as it would
549 increase the memory utilization as
550 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000551 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700552 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000553 cFYI(DBG2,
554 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700555 msleep(timeout);
556 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000557 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 if (atomic_read(&pSMBFile->wrtPending))
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000559 cERROR(1, ("close with pending write"));
560 if (!pTcon->need_reconnect &&
561 !pSMBFile->invalidHandle)
562 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000564 } else
565 write_unlock(&GlobalSMBSeslock);
566 } else
567 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000568
569 /* Delete any outstanding lock records.
570 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000571 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000572 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
573 list_del(&li->llist);
574 kfree(li);
575 }
Roland Dreier796e5662007-05-03 04:33:45 +0000576 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000577
Steve Frenchcbe04762005-04-28 22:41:05 -0700578 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 list_del(&pSMBFile->flist);
580 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700581 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000582 timeout = 10;
583 /* We waited above to give the SMBWrite a chance to issue
584 on the wire (so we do not get SMBWrite returning EBADF
585 if writepages is racing with close. Note that writepages
586 does not specify a file handle, so it is possible for a file
587 to be opened twice, and the application close the "wrong"
588 file handle - in these cases we delay long enough to allow
589 the SMBWrite to get on the wire before the SMB Close.
590 We allow total wait here over 45 seconds, more than
591 oplock break time, and more than enough to allow any write
592 to complete on the server, or to time out on the client */
593 while ((atomic_read(&pSMBFile->wrtPending) != 0)
594 && (timeout <= 50000)) {
595 cERROR(1, ("writes pending, delay free of handle"));
596 msleep(timeout);
597 timeout *= 8;
598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 kfree(file->private_data);
600 file->private_data = NULL;
601 } else
602 rc = -EBADF;
603
Steve French4efa53f2007-09-11 05:50:53 +0000604 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 if (list_empty(&(CIFS_I(inode)->openFileList))) {
606 cFYI(1, ("closing last open instance for inode %p", inode));
607 /* if the file is not open we do not know if we can cache info
608 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000609 CIFS_I(inode)->clientCanCacheRead = false;
610 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
Steve French4efa53f2007-09-11 05:50:53 +0000612 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 rc = CIFS_I(inode)->write_behind_rc;
615 FreeXid(xid);
616 return rc;
617}
618
619int cifs_closedir(struct inode *inode, struct file *file)
620{
621 int rc = 0;
622 int xid;
623 struct cifsFileInfo *pCFileStruct =
624 (struct cifsFileInfo *)file->private_data;
625 char *ptmp;
626
Steve French26a21b92006-05-31 18:05:34 +0000627 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 xid = GetXid();
630
631 if (pCFileStruct) {
632 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000633 struct cifs_sb_info *cifs_sb =
634 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 pTcon = cifs_sb->tcon;
637
638 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000639 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000640 if (!pCFileStruct->srch_inf.endOfSearch &&
641 !pCFileStruct->invalidHandle) {
642 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000643 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
645 cFYI(1, ("Closing uncompleted readdir with rc %d",
646 rc));
647 /* not much we can do if it fails anyway, ignore rc */
648 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000649 } else
650 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
652 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800653 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000655 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000656 cifs_small_buf_release(ptmp);
657 else
658 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 kfree(file->private_data);
661 file->private_data = NULL;
662 }
663 /* BB can we lock the filestruct while this is going on? */
664 FreeXid(xid);
665 return rc;
666}
667
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000668static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
669 __u64 offset, __u8 lockType)
670{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 struct cifsLockInfo *li =
672 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000673 if (li == NULL)
674 return -ENOMEM;
675 li->offset = offset;
676 li->length = len;
677 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000678 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000679 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000680 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000681 return 0;
682}
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
685{
686 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 __u32 numLock = 0;
688 __u32 numUnlock = 0;
689 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000690 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000692 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000693 __u16 netfid;
694 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000695 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 length = 1 + pfLock->fl_end - pfLock->fl_start;
698 rc = -EACCES;
699 xid = GetXid();
700
701 cFYI(1, ("Lock parm: 0x%x flockflags: "
702 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000703 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
704 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000707 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000709 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000711 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000712 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 }
714 if (pfLock->fl_flags & FL_ACCESS)
715 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000716 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (pfLock->fl_flags & FL_LEASE)
718 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000719 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
721 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
722
723 if (pfLock->fl_type == F_WRLCK) {
724 cFYI(1, ("F_WRLCK "));
725 numLock = 1;
726 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000727 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000729 /* Check if unlock includes more than
730 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000732 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 lockType |= LOCKING_ANDX_SHARED_LOCK;
734 numLock = 1;
735 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000736 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 numLock = 1;
738 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000739 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 lockType |= LOCKING_ANDX_SHARED_LOCK;
741 numLock = 1;
742 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000743 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800745 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000746 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 if (file->private_data == NULL) {
749 FreeXid(xid);
750 return -EBADF;
751 }
Steve French08547b02006-02-28 22:39:25 +0000752 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Steve French13a6e422008-12-02 17:24:33 +0000754 if ((tcon->ses->capabilities & CAP_UNIX) &&
755 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000756 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000757 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000758 /* BB add code here to normalize offset and length to
759 account for negative length which we can not accept over the
760 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000762 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000763 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000764 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000765 posix_lock_type = CIFS_RDLCK;
766 else
767 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000768 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000769 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000770 posix_lock_type, wait_flag);
771 FreeXid(xid);
772 return rc;
773 }
774
775 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000776 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000777 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000779 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 pfLock->fl_start, 1 /* numUnlock */ ,
781 0 /* numLock */ , lockType,
782 0 /* wait flag */ );
783 pfLock->fl_type = F_UNLCK;
784 if (rc != 0)
785 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000786 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 rc = 0;
788
789 } else {
790 /* if rc == ERR_SHARING_VIOLATION ? */
791 rc = 0; /* do not change lock type to unlock
792 since range in use */
793 }
794
795 FreeXid(xid);
796 return rc;
797 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000798
799 if (!numLock && !numUnlock) {
800 /* if no lock or unlock then nothing
801 to do since we do not know what it is */
802 FreeXid(xid);
803 return -EOPNOTSUPP;
804 }
805
806 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000807 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000808 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000809 posix_lock_type = CIFS_RDLCK;
810 else
811 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000812
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000813 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000814 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000815
Steve French13a6e422008-12-02 17:24:33 +0000816 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000817 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000818 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000819 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000820 struct cifsFileInfo *fid =
821 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000822
823 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000824 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000825 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000826 0, numLock, lockType, wait_flag);
827
828 if (rc == 0) {
829 /* For Windows locks we must store them. */
830 rc = store_file_lock(fid, length,
831 pfLock->fl_start, lockType);
832 }
833 } else if (numUnlock) {
834 /* For each stored lock that this unlock overlaps
835 completely, unlock it. */
836 int stored_rc = 0;
837 struct cifsLockInfo *li, *tmp;
838
Steve French6b70c952006-09-21 07:35:29 +0000839 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000840 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000841 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
842 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000843 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000844 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000845 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000846 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000847 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000848 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000849 if (stored_rc)
850 rc = stored_rc;
851
852 list_del(&li->llist);
853 kfree(li);
854 }
855 }
Roland Dreier796e5662007-05-03 04:33:45 +0000856 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857 }
858 }
859
Steve Frenchd634cc12005-08-26 14:42:59 -0500860 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 posix_lock_file_wait(file, pfLock);
862 FreeXid(xid);
863 return rc;
864}
865
866ssize_t cifs_user_write(struct file *file, const char __user *write_data,
867 size_t write_size, loff_t *poffset)
868{
869 int rc = 0;
870 unsigned int bytes_written = 0;
871 unsigned int total_written;
872 struct cifs_sb_info *cifs_sb;
873 struct cifsTconInfo *pTcon;
874 int xid, long_op;
875 struct cifsFileInfo *open_file;
876
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800877 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 pTcon = cifs_sb->tcon;
880
881 /* cFYI(1,
882 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800883 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 if (file->private_data == NULL)
886 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000887 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000888
Jeff Layton838726c2008-08-28 07:54:59 -0400889 rc = generic_write_checks(file, poffset, &write_size, 0);
890 if (rc)
891 return rc;
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800895 if (*poffset > file->f_path.dentry->d_inode->i_size)
Steve French133672e2007-11-13 22:41:37 +0000896 long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 else
Steve French133672e2007-11-13 22:41:37 +0000898 long_op = CIFS_LONG_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 for (total_written = 0; write_size > total_written;
901 total_written += bytes_written) {
902 rc = -EAGAIN;
903 while (rc == -EAGAIN) {
904 if (file->private_data == NULL) {
905 /* file has been closed on us */
906 FreeXid(xid);
907 /* if we have gotten here we have written some data
908 and blocked, and the file has been freed on us while
909 we blocked so return what we managed to write */
910 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (open_file->closePend) {
913 FreeXid(xid);
914 if (total_written)
915 return total_written;
916 else
917 return -EBADF;
918 }
919 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 /* we could deadlock if we called
921 filemap_fdatawait from here so tell
922 reopen_file not to flush data to server
923 now */
Steve French4b18f2a2008-04-29 00:06:05 +0000924 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 if (rc != 0)
926 break;
927 }
928
929 rc = CIFSSMBWrite(xid, pTcon,
930 open_file->netfid,
931 min_t(const int, cifs_sb->wsize,
932 write_size - total_written),
933 *poffset, &bytes_written,
934 NULL, write_data + total_written, long_op);
935 }
936 if (rc || (bytes_written == 0)) {
937 if (total_written)
938 break;
939 else {
940 FreeXid(xid);
941 return rc;
942 }
943 } else
944 *poffset += bytes_written;
Steve French133672e2007-11-13 22:41:37 +0000945 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 15 seconds is plenty */
947 }
948
Steve Frencha4544342005-08-24 13:59:35 -0700949 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +0000952 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
953 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000954/* Do not update local mtime - server will set its actual value on write
955 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +0000956 * current_fs_time(inode->i_sb);*/
957 if (total_written > 0) {
958 spin_lock(&inode->i_lock);
959 if (*poffset > file->f_path.dentry->d_inode->i_size)
960 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 *poffset);
Steve French3677db12007-02-26 16:46:11 +0000962 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000964 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 }
966 FreeXid(xid);
967 return total_written;
968}
969
970static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -0400971 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 int rc = 0;
974 unsigned int bytes_written = 0;
975 unsigned int total_written;
976 struct cifs_sb_info *cifs_sb;
977 struct cifsTconInfo *pTcon;
978 int xid, long_op;
979 struct cifsFileInfo *open_file;
980
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800981 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 pTcon = cifs_sb->tcon;
984
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000985 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800986 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 if (file->private_data == NULL)
989 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000990 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800994 if (*poffset > file->f_path.dentry->d_inode->i_size)
Steve French133672e2007-11-13 22:41:37 +0000995 long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 else
Steve French133672e2007-11-13 22:41:37 +0000997 long_op = CIFS_LONG_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
999 for (total_written = 0; write_size > total_written;
1000 total_written += bytes_written) {
1001 rc = -EAGAIN;
1002 while (rc == -EAGAIN) {
1003 if (file->private_data == NULL) {
1004 /* file has been closed on us */
1005 FreeXid(xid);
1006 /* if we have gotten here we have written some data
1007 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001008 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 write */
1010 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (open_file->closePend) {
1013 FreeXid(xid);
1014 if (total_written)
1015 return total_written;
1016 else
1017 return -EBADF;
1018 }
1019 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 /* we could deadlock if we called
1021 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001022 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001024 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if (rc != 0)
1026 break;
1027 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001028 if (experimEnabled || (pTcon->ses->server &&
1029 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001030 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001031 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001032 struct kvec iov[2];
1033 unsigned int len;
1034
Steve French0ae0efa2005-10-10 10:57:19 -07001035 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001036 write_size - total_written);
1037 /* iov[0] is reserved for smb header */
1038 iov[1].iov_base = (char *)write_data +
1039 total_written;
1040 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001041 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001042 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001043 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001044 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001045 } else
Steve French60808232006-04-22 15:53:05 +00001046 rc = CIFSSMBWrite(xid, pTcon,
1047 open_file->netfid,
1048 min_t(const int, cifs_sb->wsize,
1049 write_size - total_written),
1050 *poffset, &bytes_written,
1051 write_data + total_written,
1052 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 if (rc || (bytes_written == 0)) {
1055 if (total_written)
1056 break;
1057 else {
1058 FreeXid(xid);
1059 return rc;
1060 }
1061 } else
1062 *poffset += bytes_written;
Steve French133672e2007-11-13 22:41:37 +00001063 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 15 seconds is plenty */
1065 }
1066
Steve Frencha4544342005-08-24 13:59:35 -07001067 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001070 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001071/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001072/* file->f_path.dentry->d_inode->i_ctime =
1073 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1074 if (total_written > 0) {
1075 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1076 if (*poffset > file->f_path.dentry->d_inode->i_size)
1077 i_size_write(file->f_path.dentry->d_inode,
1078 *poffset);
1079 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
Steve French3677db12007-02-26 16:46:11 +00001081 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083 FreeXid(xid);
1084 return total_written;
1085}
1086
Steve French630f3f0c2007-10-25 21:17:17 +00001087#ifdef CONFIG_CIFS_EXPERIMENTAL
1088struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1089{
1090 struct cifsFileInfo *open_file = NULL;
1091
1092 read_lock(&GlobalSMBSeslock);
1093 /* we could simply get the first_list_entry since write-only entries
1094 are always at the end of the list but since the first entry might
1095 have a close pending, we go through the whole list */
1096 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1097 if (open_file->closePend)
1098 continue;
1099 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1100 (open_file->pfile->f_flags & O_RDONLY))) {
1101 if (!open_file->invalidHandle) {
1102 /* found a good file */
1103 /* lock it so it will not be closed on us */
1104 atomic_inc(&open_file->wrtPending);
1105 read_unlock(&GlobalSMBSeslock);
1106 return open_file;
1107 } /* else might as well continue, and look for
1108 another, or simply have the caller reopen it
1109 again rather than trying to fix this handle */
1110 } else /* write only file */
1111 break; /* write only files are last so must be done */
1112 }
1113 read_unlock(&GlobalSMBSeslock);
1114 return NULL;
1115}
1116#endif
1117
Steve Frenchdd99cd82005-10-05 19:32:49 -07001118struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001119{
1120 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001121 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001122 int rc;
Steve French6148a742005-10-05 12:23:19 -07001123
Steve French60808232006-04-22 15:53:05 +00001124 /* Having a null inode here (because mapping->host was set to zero by
1125 the VFS or MM) should not happen but we had reports of on oops (due to
1126 it being zero) during stress testcases so we need to check for it */
1127
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001128 if (cifs_inode == NULL) {
1129 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001130 dump_stack();
1131 return NULL;
1132 }
1133
Steve French6148a742005-10-05 12:23:19 -07001134 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001135refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001136 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001137 if (open_file->closePend ||
1138 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001139 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001140
Steve French6148a742005-10-05 12:23:19 -07001141 if (open_file->pfile &&
1142 ((open_file->pfile->f_flags & O_RDWR) ||
1143 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001144 atomic_inc(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001145
1146 if (!open_file->invalidHandle) {
1147 /* found a good writable file */
1148 read_unlock(&GlobalSMBSeslock);
1149 return open_file;
1150 }
Steve French8840dee2007-11-16 23:05:52 +00001151
Steve French6148a742005-10-05 12:23:19 -07001152 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001153 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001154 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001155 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001156 if (!open_file->closePend)
1157 return open_file;
1158 else { /* start over in case this was deleted */
1159 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001160 read_lock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +00001161 atomic_dec(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001162 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001163 }
1164 }
Steve French9b22b0b2007-10-02 01:11:08 +00001165
1166 /* if it fails, try another handle if possible -
1167 (we can not do this if closePending since
1168 loop could be modified - in which case we
1169 have to start at the beginning of the list
1170 again. Note that it would be bad
1171 to hold up writepages here (rather than
1172 in caller) with continuous retries */
1173 cFYI(1, ("wp failed on reopen file"));
1174 read_lock(&GlobalSMBSeslock);
1175 /* can not use this handle, no write
1176 pending on this one after all */
1177 atomic_dec(&open_file->wrtPending);
Steve French8840dee2007-11-16 23:05:52 +00001178
Steve French9b22b0b2007-10-02 01:11:08 +00001179 if (open_file->closePend) /* list could have changed */
1180 goto refind_writable;
1181 /* else we simply continue to the next entry. Thus
1182 we do not loop on reopen errors. If we
1183 can not reopen the file, for example if we
1184 reconnected to a server with another client
1185 racing to delete or lock the file we would not
1186 make progress if we restarted before the beginning
1187 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001188 }
1189 }
Jeff Layton2846d382008-09-22 21:33:33 -04001190 /* couldn't find useable FH with same pid, try any available */
1191 if (!any_available) {
1192 any_available = true;
1193 goto refind_writable;
1194 }
Steve French6148a742005-10-05 12:23:19 -07001195 read_unlock(&GlobalSMBSeslock);
1196 return NULL;
1197}
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1200{
1201 struct address_space *mapping = page->mapping;
1202 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1203 char *write_data;
1204 int rc = -EFAULT;
1205 int bytes_written = 0;
1206 struct cifs_sb_info *cifs_sb;
1207 struct cifsTconInfo *pTcon;
1208 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001209 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 if (!mapping || !mapping->host)
1212 return -EFAULT;
1213
1214 inode = page->mapping->host;
1215 cifs_sb = CIFS_SB(inode->i_sb);
1216 pTcon = cifs_sb->tcon;
1217
1218 offset += (loff_t)from;
1219 write_data = kmap(page);
1220 write_data += from;
1221
1222 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1223 kunmap(page);
1224 return -EIO;
1225 }
1226
1227 /* racing with truncate? */
1228 if (offset > mapping->host->i_size) {
1229 kunmap(page);
1230 return 0; /* don't care */
1231 }
1232
1233 /* check to make sure that we are not extending the file */
1234 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001235 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Steve French6148a742005-10-05 12:23:19 -07001237 open_file = find_writable_file(CIFS_I(mapping->host));
1238 if (open_file) {
1239 bytes_written = cifs_write(open_file->pfile, write_data,
1240 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001241 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001243 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001244 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001245 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001246 else if (bytes_written < 0)
1247 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001248 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 cFYI(1, ("No writeable filehandles for inode"));
1250 rc = -EIO;
1251 }
1252
1253 kunmap(page);
1254 return rc;
1255}
1256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001258 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
Steve French37c0eb42005-10-05 14:50:29 -07001260 struct backing_dev_info *bdi = mapping->backing_dev_info;
1261 unsigned int bytes_to_write;
1262 unsigned int bytes_written;
1263 struct cifs_sb_info *cifs_sb;
1264 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001265 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001266 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001267 int range_whole = 0;
1268 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001269 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001270 int n_iov = 0;
1271 pgoff_t next;
1272 int nr_pages;
1273 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001274 struct cifsFileInfo *open_file;
Steve French37c0eb42005-10-05 14:50:29 -07001275 struct page *page;
1276 struct pagevec pvec;
1277 int rc = 0;
1278 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 int xid;
1280
Steve French37c0eb42005-10-05 14:50:29 -07001281 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001282
Steve French37c0eb42005-10-05 14:50:29 -07001283 /*
1284 * If wsize is smaller that the page cache size, default to writing
1285 * one page at a time via cifs_writepage
1286 */
1287 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1288 return generic_writepages(mapping, wbc);
1289
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001290 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1291 if (cifs_sb->tcon->ses->server->secMode &
1292 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1293 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001294 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001295
Steve French9a0c8232007-02-02 04:21:57 +00001296 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001297 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001298 return generic_writepages(mapping, wbc);
1299
1300
Steve French37c0eb42005-10-05 14:50:29 -07001301 /*
1302 * BB: Is this meaningful for a non-block-device file system?
1303 * If it is, we should test it again after we do I/O
1304 */
1305 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1306 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001307 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001308 return 0;
1309 }
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 xid = GetXid();
1312
Steve French37c0eb42005-10-05 14:50:29 -07001313 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001314 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001315 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001316 end = -1;
1317 } else {
1318 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1319 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1320 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1321 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001322 scanned = 1;
1323 }
1324retry:
1325 while (!done && (index <= end) &&
1326 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1327 PAGECACHE_TAG_DIRTY,
1328 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1329 int first;
1330 unsigned int i;
1331
Steve French37c0eb42005-10-05 14:50:29 -07001332 first = -1;
1333 next = 0;
1334 n_iov = 0;
1335 bytes_to_write = 0;
1336
1337 for (i = 0; i < nr_pages; i++) {
1338 page = pvec.pages[i];
1339 /*
1340 * At this point we hold neither mapping->tree_lock nor
1341 * lock on the page itself: the page may be truncated or
1342 * invalidated (changing page->mapping to NULL), or even
1343 * swizzled back from swapper_space to tmpfs file
1344 * mapping
1345 */
1346
1347 if (first < 0)
1348 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001349 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001350 break;
1351
1352 if (unlikely(page->mapping != mapping)) {
1353 unlock_page(page);
1354 break;
1355 }
1356
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001357 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001358 done = 1;
1359 unlock_page(page);
1360 break;
1361 }
1362
1363 if (next && (page->index != next)) {
1364 /* Not next consecutive page */
1365 unlock_page(page);
1366 break;
1367 }
1368
1369 if (wbc->sync_mode != WB_SYNC_NONE)
1370 wait_on_page_writeback(page);
1371
1372 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001373 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001374 unlock_page(page);
1375 break;
1376 }
Steve French84d2f072005-10-12 15:32:05 -07001377
Linus Torvaldscb876f42006-12-23 16:19:07 -08001378 /*
1379 * This actually clears the dirty bit in the radix tree.
1380 * See cifs_writepage() for more commentary.
1381 */
1382 set_page_writeback(page);
1383
Steve French84d2f072005-10-12 15:32:05 -07001384 if (page_offset(page) >= mapping->host->i_size) {
1385 done = 1;
1386 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001387 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001388 break;
1389 }
1390
Steve French37c0eb42005-10-05 14:50:29 -07001391 /*
1392 * BB can we get rid of this? pages are held by pvec
1393 */
1394 page_cache_get(page);
1395
Steve French84d2f072005-10-12 15:32:05 -07001396 len = min(mapping->host->i_size - page_offset(page),
1397 (loff_t)PAGE_CACHE_SIZE);
1398
Steve French37c0eb42005-10-05 14:50:29 -07001399 /* reserve iov[0] for the smb header */
1400 n_iov++;
1401 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001402 iov[n_iov].iov_len = len;
1403 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001404
1405 if (first < 0) {
1406 first = i;
1407 offset = page_offset(page);
1408 }
1409 next = page->index + 1;
1410 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1411 break;
1412 }
1413 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001414 /* Search for a writable handle every time we call
1415 * CIFSSMBWrite2. We can't rely on the last handle
1416 * we used to still be valid
1417 */
1418 open_file = find_writable_file(CIFS_I(mapping->host));
1419 if (!open_file) {
1420 cERROR(1, ("No writable handles for inode"));
1421 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001422 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001423 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1424 open_file->netfid,
1425 bytes_to_write, offset,
1426 &bytes_written, iov, n_iov,
Steve French133672e2007-11-13 22:41:37 +00001427 CIFS_LONG_OP);
Steve French23e7dd72005-10-20 13:44:56 -07001428 atomic_dec(&open_file->wrtPending);
1429 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001430 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001431 rc, bytes_written));
1432 /* BB what if continued retry is
1433 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001434 if (rc == -ENOSPC)
1435 set_bit(AS_ENOSPC, &mapping->flags);
1436 else
1437 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001438 } else {
1439 cifs_stats_bytes_written(cifs_sb->tcon,
1440 bytes_written);
1441 }
Steve French37c0eb42005-10-05 14:50:29 -07001442 }
1443 for (i = 0; i < n_iov; i++) {
1444 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001445 /* Should we also set page error on
1446 success rc but too little data written? */
1447 /* BB investigate retry logic on temporary
1448 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001449 when page marked as error */
1450 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001451 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001452 kunmap(page);
1453 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001454 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001455 page_cache_release(page);
1456 }
1457 if ((wbc->nr_to_write -= n_iov) <= 0)
1458 done = 1;
1459 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001460 } else
1461 /* Need to re-find the pages we skipped */
1462 index = pvec.pages[0]->index + 1;
1463
Steve French37c0eb42005-10-05 14:50:29 -07001464 pagevec_release(&pvec);
1465 }
1466 if (!scanned && !done) {
1467 /*
1468 * We hit the last page and there is more work to be done: wrap
1469 * back to the start of the file
1470 */
1471 scanned = 1;
1472 index = 0;
1473 goto retry;
1474 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001475 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001476 mapping->writeback_index = index;
1477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001479 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return rc;
1481}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001483static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
1485 int rc = -EFAULT;
1486 int xid;
1487
1488 xid = GetXid();
1489/* BB add check for wbc flags */
1490 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001491 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001493
1494 /*
1495 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1496 *
1497 * A writepage() implementation always needs to do either this,
1498 * or re-dirty the page with "redirty_page_for_writepage()" in
1499 * the case of a failure.
1500 *
1501 * Just unlocking the page will cause the radix tree tag-bits
1502 * to fail to update with the state of the page correctly.
1503 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001504 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1506 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1507 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001508 end_page_writeback(page);
1509 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 FreeXid(xid);
1511 return rc;
1512}
1513
Nick Piggind9414772008-09-24 11:32:59 -04001514static int cifs_write_end(struct file *file, struct address_space *mapping,
1515 loff_t pos, unsigned len, unsigned copied,
1516 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517{
Nick Piggind9414772008-09-24 11:32:59 -04001518 int rc;
1519 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Nick Piggind9414772008-09-24 11:32:59 -04001521 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1522 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001523
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001524 if (PageChecked(page)) {
1525 if (copied == len)
1526 SetPageUptodate(page);
1527 ClearPageChecked(page);
1528 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001529 SetPageUptodate(page);
1530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001532 char *page_data;
1533 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1534 int xid;
1535
1536 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /* this is probably better than directly calling
1538 partialpage_write since in this function the file handle is
1539 known which we might as well leverage */
1540 /* BB check if anything else missing out of ppw
1541 such as updating last write time */
1542 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001543 rc = cifs_write(file, page_data + offset, copied, &pos);
1544 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001546
1547 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001548 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001549 rc = copied;
1550 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 set_page_dirty(page);
1552 }
1553
Nick Piggind9414772008-09-24 11:32:59 -04001554 if (rc > 0) {
1555 spin_lock(&inode->i_lock);
1556 if (pos > inode->i_size)
1557 i_size_write(inode, pos);
1558 spin_unlock(&inode->i_lock);
1559 }
1560
1561 unlock_page(page);
1562 page_cache_release(page);
1563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 return rc;
1565}
1566
1567int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1568{
1569 int xid;
1570 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001571 struct cifsTconInfo *tcon;
1572 struct cifsFileInfo *smbfile =
1573 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001574 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 xid = GetXid();
1577
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001578 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001580
Jeff Laytoncea21802007-11-20 23:19:03 +00001581 rc = filemap_write_and_wait(inode->i_mapping);
1582 if (rc == 0) {
1583 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001585 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001586 if (!rc && tcon && smbfile &&
1587 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_SSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001588 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001589 }
Steve Frenchb298f222009-02-21 21:17:43 +00001590
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 FreeXid(xid);
1592 return rc;
1593}
1594
NeilBrown3978d7172006-03-26 01:37:17 -08001595/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596{
1597 struct address_space *mapping;
1598 struct inode *inode;
1599 unsigned long index = page->index;
1600 unsigned int rpages = 0;
1601 int rc = 0;
1602
1603 cFYI(1, ("sync page %p",page));
1604 mapping = page->mapping;
1605 if (!mapping)
1606 return 0;
1607 inode = mapping->host;
1608 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001609 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001611/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1613
Steve French26a21b92006-05-31 18:05:34 +00001614/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
NeilBrown3978d7172006-03-26 01:37:17 -08001616#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (rc < 0)
1618 return rc;
1619 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001620#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621} */
1622
1623/*
1624 * As file closes, flush all cached write data for this inode checking
1625 * for write behind errors.
1626 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001627int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001629 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 int rc = 0;
1631
1632 /* Rather than do the steps manually:
1633 lock the inode for writing
1634 loop through pages looking for write behind data (dirty pages)
1635 coalesce into contiguous 16K (or smaller) chunks to write to server
1636 send to server (prefer in parallel)
1637 deal with writebehind errors
1638 unlock inode for writing
1639 filemapfdatawrite appears easier for the time being */
1640
1641 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001642 /* reset wb rc if we were able to write out dirty pages */
1643 if (!rc) {
1644 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001646 }
Steve French50c2f752007-07-13 00:33:32 +00001647
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001648 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 return rc;
1651}
1652
1653ssize_t cifs_user_read(struct file *file, char __user *read_data,
1654 size_t read_size, loff_t *poffset)
1655{
1656 int rc = -EACCES;
1657 unsigned int bytes_read = 0;
1658 unsigned int total_read = 0;
1659 unsigned int current_read_size;
1660 struct cifs_sb_info *cifs_sb;
1661 struct cifsTconInfo *pTcon;
1662 int xid;
1663 struct cifsFileInfo *open_file;
1664 char *smb_read_data;
1665 char __user *current_offset;
1666 struct smb_com_read_rsp *pSMBr;
1667
1668 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001669 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 pTcon = cifs_sb->tcon;
1671
1672 if (file->private_data == NULL) {
1673 FreeXid(xid);
1674 return -EBADF;
1675 }
1676 open_file = (struct cifsFileInfo *)file->private_data;
1677
Steve Frenchad7a2922008-02-07 23:25:02 +00001678 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 for (total_read = 0, current_offset = read_data;
1682 read_size > total_read;
1683 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001684 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 cifs_sb->rsize);
1686 rc = -EAGAIN;
1687 smb_read_data = NULL;
1688 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001689 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001690 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001692 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc != 0)
1694 break;
1695 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001696 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001697 open_file->netfid,
1698 current_read_size, *poffset,
1699 &bytes_read, &smb_read_data,
1700 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001703 if (copy_to_user(current_offset,
1704 smb_read_data +
1705 4 /* RFC1001 length field */ +
1706 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001707 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001708 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001709
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001710 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001711 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001712 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001713 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 smb_read_data = NULL;
1715 }
1716 }
1717 if (rc || (bytes_read == 0)) {
1718 if (total_read) {
1719 break;
1720 } else {
1721 FreeXid(xid);
1722 return rc;
1723 }
1724 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001725 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 *poffset += bytes_read;
1727 }
1728 }
1729 FreeXid(xid);
1730 return total_read;
1731}
1732
1733
1734static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1735 loff_t *poffset)
1736{
1737 int rc = -EACCES;
1738 unsigned int bytes_read = 0;
1739 unsigned int total_read;
1740 unsigned int current_read_size;
1741 struct cifs_sb_info *cifs_sb;
1742 struct cifsTconInfo *pTcon;
1743 int xid;
1744 char *current_offset;
1745 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001746 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
1748 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001749 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 pTcon = cifs_sb->tcon;
1751
1752 if (file->private_data == NULL) {
1753 FreeXid(xid);
1754 return -EBADF;
1755 }
1756 open_file = (struct cifsFileInfo *)file->private_data;
1757
1758 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1759 cFYI(1, ("attempting read on write only file instance"));
1760
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001761 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 read_size > total_read;
1763 total_read += bytes_read, current_offset += bytes_read) {
1764 current_read_size = min_t(const int, read_size - total_read,
1765 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001766 /* For windows me and 9x we do not want to request more
1767 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001769 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1770 current_read_size = min_t(const int, current_read_size,
1771 pTcon->ses->server->maxBuf - 128);
1772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 rc = -EAGAIN;
1774 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001777 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (rc != 0)
1779 break;
1780 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001781 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001782 open_file->netfid,
1783 current_read_size, *poffset,
1784 &bytes_read, &current_offset,
1785 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 }
1787 if (rc || (bytes_read == 0)) {
1788 if (total_read) {
1789 break;
1790 } else {
1791 FreeXid(xid);
1792 return rc;
1793 }
1794 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001795 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 *poffset += bytes_read;
1797 }
1798 }
1799 FreeXid(xid);
1800 return total_read;
1801}
1802
1803int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1804{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001805 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 int rc, xid;
1807
1808 xid = GetXid();
1809 rc = cifs_revalidate(dentry);
1810 if (rc) {
1811 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1812 FreeXid(xid);
1813 return rc;
1814 }
1815 rc = generic_file_mmap(file, vma);
1816 FreeXid(xid);
1817 return rc;
1818}
1819
1820
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 struct list_head *pages, int bytes_read, char *data,
1823 struct pagevec *plru_pvec)
1824{
1825 struct page *page;
1826 char *target;
1827
1828 while (bytes_read > 0) {
1829 if (list_empty(pages))
1830 break;
1831
1832 page = list_entry(pages->prev, struct page, lru);
1833 list_del(&page->lru);
1834
1835 if (add_to_page_cache(page, mapping, page->index,
1836 GFP_KERNEL)) {
1837 page_cache_release(page);
1838 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001839 data += PAGE_CACHE_SIZE;
1840 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 continue;
1842 }
1843
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001844 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 if (PAGE_CACHE_SIZE > bytes_read) {
1847 memcpy(target, data, bytes_read);
1848 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001849 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 PAGE_CACHE_SIZE - bytes_read);
1851 bytes_read = 0;
1852 } else {
1853 memcpy(target, data, PAGE_CACHE_SIZE);
1854 bytes_read -= PAGE_CACHE_SIZE;
1855 }
1856 kunmap_atomic(target, KM_USER0);
1857
1858 flush_dcache_page(page);
1859 SetPageUptodate(page);
1860 unlock_page(page);
1861 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001862 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 data += PAGE_CACHE_SIZE;
1864 }
1865 return;
1866}
1867
1868static int cifs_readpages(struct file *file, struct address_space *mapping,
1869 struct list_head *page_list, unsigned num_pages)
1870{
1871 int rc = -EACCES;
1872 int xid;
1873 loff_t offset;
1874 struct page *page;
1875 struct cifs_sb_info *cifs_sb;
1876 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001877 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001878 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 char *smb_read_data = NULL;
1880 struct smb_com_read_rsp *pSMBr;
1881 struct pagevec lru_pvec;
1882 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001883 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
1885 xid = GetXid();
1886 if (file->private_data == NULL) {
1887 FreeXid(xid);
1888 return -EBADF;
1889 }
1890 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001891 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00001895 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 for (i = 0; i < num_pages; ) {
1897 unsigned contig_pages;
1898 struct page *tmp_page;
1899 unsigned long expected_index;
1900
1901 if (list_empty(page_list))
1902 break;
1903
1904 page = list_entry(page_list->prev, struct page, lru);
1905 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1906
1907 /* count adjacent pages that we will read into */
1908 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001909 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001911 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 if (tmp_page->index == expected_index) {
1913 contig_pages++;
1914 expected_index++;
1915 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001916 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 }
1918 if (contig_pages + i > num_pages)
1919 contig_pages = num_pages - i;
1920
1921 /* for reads over a certain size could initiate async
1922 read ahead */
1923
1924 read_size = contig_pages * PAGE_CACHE_SIZE;
1925 /* Read size needs to be in multiples of one page */
1926 read_size = min_t(const unsigned int, read_size,
1927 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00001928 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00001929 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 rc = -EAGAIN;
1931 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001932 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001934 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (rc != 0)
1936 break;
1937 }
1938
Steve Frenchbfa0d752005-08-31 21:50:37 -07001939 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001940 open_file->netfid,
1941 read_size, offset,
1942 &bytes_read, &smb_read_data,
1943 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001944 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001945 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001947 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001948 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001949 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001950 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 smb_read_data = NULL;
1952 }
1953 }
1954 }
1955 if ((rc < 0) || (smb_read_data == NULL)) {
1956 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 break;
1958 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001959 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1961 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1962 smb_read_data + 4 /* RFC1001 hdr */ +
1963 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1964
1965 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001966 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001967 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 i++; /* account for partial page */
1969
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001970 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001972 /* BB do we need to verify this common case ?
1973 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 we will hit it on next read */
1975
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001976 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 }
1978 } else {
1979 cFYI(1, ("No bytes read (%d) at offset %lld . "
1980 "Cleaning remaining pages from readahead list",
1981 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001982 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 break;
1985 }
1986 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001988 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001990 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 smb_read_data = NULL;
1992 }
1993 bytes_read = 0;
1994 }
1995
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001996 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
1998/* need to free smb_read_data buf before exit */
1999 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002000 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002001 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002002 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002003 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
2007 FreeXid(xid);
2008 return rc;
2009}
2010
2011static int cifs_readpage_worker(struct file *file, struct page *page,
2012 loff_t *poffset)
2013{
2014 char *read_data;
2015 int rc;
2016
2017 page_cache_get(page);
2018 read_data = kmap(page);
2019 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 if (rc < 0)
2024 goto io_error;
2025 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002026 cFYI(1, ("Bytes read %d", rc));
2027
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002028 file->f_path.dentry->d_inode->i_atime =
2029 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 if (PAGE_CACHE_SIZE > rc)
2032 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2033
2034 flush_dcache_page(page);
2035 SetPageUptodate(page);
2036 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002039 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 page_cache_release(page);
2041 return rc;
2042}
2043
2044static int cifs_readpage(struct file *file, struct page *page)
2045{
2046 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2047 int rc = -EACCES;
2048 int xid;
2049
2050 xid = GetXid();
2051
2052 if (file->private_data == NULL) {
2053 FreeXid(xid);
2054 return -EBADF;
2055 }
2056
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 page, (int)offset, (int)offset));
2059
2060 rc = cifs_readpage_worker(file, page, &offset);
2061
2062 unlock_page(page);
2063
2064 FreeXid(xid);
2065 return rc;
2066}
2067
Steve Frencha403a0a2007-07-26 15:54:16 +00002068static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2069{
2070 struct cifsFileInfo *open_file;
2071
2072 read_lock(&GlobalSMBSeslock);
2073 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2074 if (open_file->closePend)
2075 continue;
2076 if (open_file->pfile &&
2077 ((open_file->pfile->f_flags & O_RDWR) ||
2078 (open_file->pfile->f_flags & O_WRONLY))) {
2079 read_unlock(&GlobalSMBSeslock);
2080 return 1;
2081 }
2082 }
2083 read_unlock(&GlobalSMBSeslock);
2084 return 0;
2085}
2086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087/* We do not want to update the file size from server for inodes
2088 open for write - to avoid races with writepage extending
2089 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 but this is tricky to do without racing with writebehind
2092 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002093bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094{
Steve Frencha403a0a2007-07-26 15:54:16 +00002095 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002096 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002097
Steve Frencha403a0a2007-07-26 15:54:16 +00002098 if (is_inode_writable(cifsInode)) {
2099 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002100 struct cifs_sb_info *cifs_sb;
2101
Steve Frenchc32a0b62006-01-12 14:41:28 -08002102 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002103 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002104 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002105 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002106 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002107 }
2108
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002109 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002110 return true;
Steve French7ba52632007-02-08 18:14:13 +00002111
Steve French4b18f2a2008-04-29 00:06:05 +00002112 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002113 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002114 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115}
2116
Nick Piggind9414772008-09-24 11:32:59 -04002117static int cifs_write_begin(struct file *file, struct address_space *mapping,
2118 loff_t pos, unsigned len, unsigned flags,
2119 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
Nick Piggind9414772008-09-24 11:32:59 -04002121 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2122 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002123 loff_t page_start = pos & PAGE_MASK;
2124 loff_t i_size;
2125 struct page *page;
2126 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
Nick Piggind9414772008-09-24 11:32:59 -04002128 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2129
Nick Piggin54566b22009-01-04 12:00:53 -08002130 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002131 if (!page) {
2132 rc = -ENOMEM;
2133 goto out;
2134 }
Nick Piggind9414772008-09-24 11:32:59 -04002135
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002136 if (PageUptodate(page))
2137 goto out;
Steve French8a236262007-03-06 00:31:00 +00002138
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002139 /*
2140 * If we write a full page it will be up to date, no need to read from
2141 * the server. If the write is short, we'll end up doing a sync write
2142 * instead.
2143 */
2144 if (len == PAGE_CACHE_SIZE)
2145 goto out;
2146
2147 /*
2148 * optimize away the read when we have an oplock, and we're not
2149 * expecting to use any of the data we'd be reading in. That
2150 * is, when the page lies beyond the EOF, or straddles the EOF
2151 * and the write will cover all of the existing data.
2152 */
2153 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2154 i_size = i_size_read(mapping->host);
2155 if (page_start >= i_size ||
2156 (offset == 0 && (pos + len) >= i_size)) {
2157 zero_user_segments(page, 0, offset,
2158 offset + len,
2159 PAGE_CACHE_SIZE);
2160 /*
2161 * PageChecked means that the parts of the page
2162 * to which we're not writing are considered up
2163 * to date. Once the data is copied to the
2164 * page, it can be set uptodate.
2165 */
2166 SetPageChecked(page);
2167 goto out;
2168 }
2169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Nick Piggind9414772008-09-24 11:32:59 -04002171 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002172 /*
2173 * might as well read a page, it is fast enough. If we get
2174 * an error, we don't need to return it. cifs_write_end will
2175 * do a sync write instead since PG_uptodate isn't set.
2176 */
2177 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002178 } else {
2179 /* we could try using another file handle if there is one -
2180 but how would we lock it to prevent close of that handle
2181 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002182 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002183 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002184out:
2185 *pagep = page;
2186 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187}
2188
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002189const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 .readpage = cifs_readpage,
2191 .readpages = cifs_readpages,
2192 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002193 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002194 .write_begin = cifs_write_begin,
2195 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 .set_page_dirty = __set_page_dirty_nobuffers,
2197 /* .sync_page = cifs_sync_page, */
2198 /* .direct_IO = */
2199};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002200
2201/*
2202 * cifs_readpages requires the server to support a buffer large enough to
2203 * contain the header plus one complete page of data. Otherwise, we need
2204 * to leave cifs_readpages out of the address space operations.
2205 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002206const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002207 .readpage = cifs_readpage,
2208 .writepage = cifs_writepage,
2209 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002210 .write_begin = cifs_write_begin,
2211 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002212 .set_page_dirty = __set_page_dirty_nobuffers,
2213 /* .sync_page = cifs_sync_page, */
2214 /* .direct_IO = */
2215};