blob: 50ca088d8860665e5ed5e128a899101ec08a007a [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;
Steve Frencha6ce4932009-04-09 01:14:32 +000049 mutex_init(&private_data->fh_mutex);
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 */
Steve French276a74a2009-03-03 18:00:34 +0000128static inline int cifs_posix_open_inode_helper(struct inode *inode,
129 struct file *file, struct cifsInodeInfo *pCifsInode,
130 struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
131{
132 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
133/* struct timespec temp; */ /* BB REMOVEME BB */
134
135 file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
136 if (file->private_data == NULL)
137 return -ENOMEM;
138 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
139 write_lock(&GlobalSMBSeslock);
140 list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
141
142 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
143 if (pCifsInode == NULL) {
144 write_unlock(&GlobalSMBSeslock);
145 return -EINVAL;
146 }
147
148 /* want handles we can use to read with first
149 in the list so we do not have to walk the
150 list to search for one in write_begin */
151 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
152 list_add_tail(&pCifsFile->flist,
153 &pCifsInode->openFileList);
154 } else {
155 list_add(&pCifsFile->flist,
156 &pCifsInode->openFileList);
157 }
158
159 if (pCifsInode->clientCanCacheRead) {
160 /* we have the inode open somewhere else
161 no need to discard cache data */
162 goto psx_client_can_cache;
163 }
164
165 /* BB FIXME need to fix this check to move it earlier into posix_open
166 BB fIX following section BB FIXME */
167
168 /* if not oplocked, invalidate inode pages if mtime or file
169 size changed */
170/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
171 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
172 (file->f_path.dentry->d_inode->i_size ==
173 (loff_t)le64_to_cpu(buf->EndOfFile))) {
174 cFYI(1, ("inode unchanged on server"));
175 } else {
176 if (file->f_path.dentry->d_inode->i_mapping) {
177 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
178 if (rc != 0)
179 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
180 }
181 cFYI(1, ("invalidating remote inode since open detected it "
182 "changed"));
183 invalidate_remote_inode(file->f_path.dentry->d_inode);
184 } */
185
186psx_client_can_cache:
187 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
188 pCifsInode->clientCanCacheAll = true;
189 pCifsInode->clientCanCacheRead = true;
190 cFYI(1, ("Exclusive Oplock granted on inode %p",
191 file->f_path.dentry->d_inode));
192 } else if ((oplock & 0xF) == OPLOCK_READ)
193 pCifsInode->clientCanCacheRead = true;
194
195 /* will have to change the unlock if we reenable the
196 filemap_fdatawrite (which does not seem necessary */
197 write_unlock(&GlobalSMBSeslock);
198 return 0;
199}
200
201/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
203 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
204 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
205 char *full_path, int xid)
206{
207 struct timespec temp;
208 int rc;
209
210 /* want handles we can use to read with first
211 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400212 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000214 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 &pCifsInode->openFileList);
216 } else {
217 list_add(&pCifsFile->flist,
218 &pCifsInode->openFileList);
219 }
220 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if (pCifsInode->clientCanCacheRead) {
222 /* we have the inode open somewhere else
223 no need to discard cache data */
224 goto client_can_cache;
225 }
226
227 /* BB need same check in cifs_create too? */
228 /* if not oplocked, invalidate inode pages if mtime or file
229 size changed */
230 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800231 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
232 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 (loff_t)le64_to_cpu(buf->EndOfFile))) {
234 cFYI(1, ("inode unchanged on server"));
235 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 /* BB no need to lock inode until after invalidate
238 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000239 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
240 if (rc != 0)
241 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243 cFYI(1, ("invalidating remote inode since open detected it "
244 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800245 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247
248client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000249 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800250 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 full_path, inode->i_sb, xid);
252 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800253 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000254 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000257 pCifsInode->clientCanCacheAll = true;
258 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800260 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000262 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 return rc;
265}
266
267int cifs_open(struct inode *inode, struct file *file)
268{
269 int rc = -EACCES;
270 int xid, oplock;
271 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000272 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct cifsFileInfo *pCifsFile;
274 struct cifsInodeInfo *pCifsInode;
275 struct list_head *tmp;
276 char *full_path = NULL;
277 int desiredAccess;
278 int disposition;
279 __u16 netfid;
280 FILE_ALL_INFO *buf = NULL;
281
282 xid = GetXid();
283
284 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000285 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Steve Frencha6ce4932009-04-09 01:14:32 +0000287 /* search inode for this file and fill in file->private_data */
288 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
289 read_lock(&GlobalSMBSeslock);
290 list_for_each(tmp, &pCifsInode->openFileList) {
291 pCifsFile = list_entry(tmp, struct cifsFileInfo,
292 flist);
293 if ((pCifsFile->pfile == NULL) &&
294 (pCifsFile->pid == current->tgid)) {
295 /* mode set in cifs_create */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Steve Frencha6ce4932009-04-09 01:14:32 +0000297 /* needed for writepage */
298 pCifsFile->pfile = file;
Steve French50c2f752007-07-13 00:33:32 +0000299
Steve Frencha6ce4932009-04-09 01:14:32 +0000300 file->private_data = pCifsFile;
301 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Steve Frencha6ce4932009-04-09 01:14:32 +0000303 }
304 read_unlock(&GlobalSMBSeslock);
305
306 if (file->private_data != NULL) {
307 rc = 0;
308 FreeXid(xid);
309 return rc;
Steve Frenchbc8cd432009-04-12 18:18:40 +0000310 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
Steve Frencha6ce4932009-04-09 01:14:32 +0000311 cERROR(1, ("could not find file instance for "
312 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800314 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (full_path == NULL) {
316 FreeXid(xid);
317 return -ENOMEM;
318 }
319
Steve French7521a3c2007-07-11 18:30:34 +0000320 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000322
323 if (oplockEnabled)
324 oplock = REQ_OPLOCK;
325 else
326 oplock = 0;
327
Steve French64cc2c62009-03-04 19:54:08 +0000328 if (!tcon->broken_posix_open && tcon->unix_ext &&
329 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000330 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
331 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
332 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
333 /* can not refresh inode info since size could be stale */
334 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
335 cifs_sb->mnt_file_mode /* ignored */,
336 oflags, &oplock, &netfid, xid);
337 if (rc == 0) {
338 cFYI(1, ("posix open succeeded"));
339 /* no need for special case handling of setting mode
340 on read only files needed here */
341
342 cifs_posix_open_inode_helper(inode, file, pCifsInode,
343 pCifsFile, oplock, netfid);
344 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000345 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
346 if (tcon->ses->serverNOS)
347 cERROR(1, ("server %s of type %s returned"
348 " unexpected error on SMB posix open"
349 ", disabling posix open support."
350 " Check if server update available.",
351 tcon->ses->serverName,
352 tcon->ses->serverNOS));
353 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000354 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
355 (rc != -EOPNOTSUPP)) /* path not found or net err */
356 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000357 /* else fallthrough to retry open the old way on network i/o
358 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000359 }
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 desiredAccess = cifs_convert_flags(file->f_flags);
362
363/*********************************************************************
364 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000365 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 * O_CREAT FILE_OPEN_IF
369 * O_CREAT | O_EXCL FILE_CREATE
370 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
371 * O_TRUNC FILE_OVERWRITE
372 * none of the above FILE_OPEN
373 *
374 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000375 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 * O_CREAT | O_TRUNC is similar but truncates the existing
377 * file rather than creating a new file as FILE_SUPERSEDE does
378 * (which uses the attributes / metadata passed in on open call)
379 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000380 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 *? and the read write flags match reasonably. O_LARGEFILE
382 *? is irrelevant because largefile support is always used
383 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
384 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
385 *********************************************************************/
386
387 disposition = cifs_get_disposition(file->f_flags);
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /* BB pass O_SYNC flag through on file attributes .. BB */
390
391 /* Also refresh inode by passing in file_info buf returned by SMBOpen
392 and calling get_inode_info with returned buf (at least helps
393 non-Unix server case) */
394
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000395 /* BB we can not do this if this is the second open of a file
396 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
398 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
399 if (!buf) {
400 rc = -ENOMEM;
401 goto out;
402 }
Steve French5bafd762006-06-07 00:18:43 +0000403
404 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000405 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000406 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700407 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
408 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000409 else
410 rc = -EIO; /* no NT SMB support fall into legacy open below */
411
Steve Frencha9d02ad2005-08-24 23:06:05 -0700412 if (rc == -EIO) {
413 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000414 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700415 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
416 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
417 & CIFS_MOUNT_MAP_SPECIAL_CHR);
418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000420 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 goto out;
422 }
423 file->private_data =
424 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
425 if (file->private_data == NULL) {
426 rc = -ENOMEM;
427 goto out;
428 }
429 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000431 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800433 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 if (pCifsInode) {
435 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000436 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 &oplock, buf, full_path, xid);
438 } else {
439 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
441
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000442 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 /* time to set mode which we can not set earlier due to
444 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000445 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400446 struct cifs_unix_set_info_args args = {
447 .mode = inode->i_mode,
448 .uid = NO_CHANGE_64,
449 .gid = NO_CHANGE_64,
450 .ctime = NO_CHANGE_64,
451 .atime = NO_CHANGE_64,
452 .mtime = NO_CHANGE_64,
453 .device = 0,
454 };
Steve French276a74a2009-03-03 18:00:34 +0000455 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
Steve French737b7582005-04-28 22:41:06 -0700456 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000457 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700458 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
460 }
461
462out:
463 kfree(buf);
464 kfree(full_path);
465 FreeXid(xid);
466 return rc;
467}
468
Adrian Bunk04187262006-06-30 18:23:04 +0200469/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470/* to server was lost */
471static int cifs_relock_file(struct cifsFileInfo *cifsFile)
472{
473 int rc = 0;
474
475/* BB list all locks open on this file and relock */
476
477 return rc;
478}
479
Steve French4b18f2a2008-04-29 00:06:05 +0000480static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 int rc = -EACCES;
483 int xid, oplock;
484 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000485 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 struct cifsFileInfo *pCifsFile;
487 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 char *full_path = NULL;
490 int desiredAccess;
491 int disposition = FILE_OPEN;
492 __u16 netfid;
493
Steve Frenchad7a2922008-02-07 23:25:02 +0000494 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000496 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return -EBADF;
498
499 xid = GetXid();
Steve Frencha6ce4932009-04-09 01:14:32 +0000500 mutex_unlock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000501 if (!pCifsFile->invalidHandle) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000502 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 FreeXid(xid);
504 return 0;
505 }
506
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800507 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000508 cERROR(1, ("no valid name if dentry freed"));
509 dump_stack();
510 rc = -EBADF;
511 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
Steve French3a9f4622007-04-04 17:10:24 +0000513
514 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000515 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000516 cERROR(1, ("inode not valid"));
517 dump_stack();
518 rc = -EBADF;
519 goto reopen_error_exit;
520 }
Steve French50c2f752007-07-13 00:33:32 +0000521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000523 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525/* can not grab rename sem here because various ops, including
526 those that already have the rename sem can end up causing writepage
527 to get called and if the server was down that means we end up here,
528 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800529 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000531 rc = -ENOMEM;
532reopen_error_exit:
Steve Frencha6ce4932009-04-09 01:14:32 +0000533 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000535 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
537
Steve French3a9f4622007-04-04 17:10:24 +0000538 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 if (oplockEnabled)
542 oplock = REQ_OPLOCK;
543 else
Steve French4b18f2a2008-04-29 00:06:05 +0000544 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Steve French7fc8f4e2009-02-23 20:43:11 +0000546 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
547 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
548 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
549 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
550 /* can not refresh inode info since size could be stale */
551 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
552 cifs_sb->mnt_file_mode /* ignored */,
553 oflags, &oplock, &netfid, xid);
554 if (rc == 0) {
555 cFYI(1, ("posix reopen succeeded"));
556 goto reopen_success;
557 }
558 /* fallthrough to retry open the old way on errors, especially
559 in the reconnect path it is important to retry hard */
560 }
561
562 desiredAccess = cifs_convert_flags(file->f_flags);
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000565 by SMBOpen and then calling get_inode_info with returned buf
566 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 and server version of file size can be stale. If we knew for sure
568 that inode was not dirty locally we could do this */
569
Steve French7fc8f4e2009-02-23 20:43:11 +0000570 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000572 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700573 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (rc) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000575 mutex_lock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000576 cFYI(1, ("cifs_open returned 0x%x", rc));
577 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000579reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000581 pCifsFile->invalidHandle = false;
Steve Frencha6ce4932009-04-09 01:14:32 +0000582 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 pCifsInode = CIFS_I(inode);
584 if (pCifsInode) {
585 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000586 rc = filemap_write_and_wait(inode->i_mapping);
587 if (rc != 0)
588 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 /* temporarily disable caching while we
590 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000591 pCifsInode->clientCanCacheAll = false;
592 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000593 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 rc = cifs_get_inode_info_unix(&inode,
595 full_path, inode->i_sb, xid);
596 else
597 rc = cifs_get_inode_info(&inode,
598 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000599 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 } /* else we are writing out data to server already
601 and could deadlock if we tried to flush data, and
602 since we do not know if we have data that would
603 invalidate the current end of file on the server
604 we can not go to the server to get the new inod
605 info */
606 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000607 pCifsInode->clientCanCacheAll = true;
608 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800610 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000612 pCifsInode->clientCanCacheRead = true;
613 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000615 pCifsInode->clientCanCacheRead = false;
616 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618 cifs_relock_file(pCifsFile);
619 }
620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 kfree(full_path);
622 FreeXid(xid);
623 return rc;
624}
625
626int cifs_close(struct inode *inode, struct file *file)
627{
628 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000629 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 struct cifs_sb_info *cifs_sb;
631 struct cifsTconInfo *pTcon;
632 struct cifsFileInfo *pSMBFile =
633 (struct cifsFileInfo *)file->private_data;
634
635 xid = GetXid();
636
637 cifs_sb = CIFS_SB(inode->i_sb);
638 pTcon = cifs_sb->tcon;
639 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000640 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000641 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000642 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (pTcon) {
644 /* no sense reconnecting to close a file that is
645 already closed */
Steve French3b795212008-11-13 19:45:32 +0000646 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000647 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000648 timeout = 2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000649 while ((atomic_read(&pSMBFile->wrtPending) != 0)
Steve French15745322007-09-07 22:23:48 +0000650 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700651 /* Give write a better chance to get to
652 server ahead of the close. We do not
653 want to add a wait_q here as it would
654 increase the memory utilization as
655 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000656 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700657 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000658 cFYI(DBG2,
659 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700660 msleep(timeout);
661 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000662 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000663 if (atomic_read(&pSMBFile->wrtPending))
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000664 cERROR(1, ("close with pending write"));
665 if (!pTcon->need_reconnect &&
666 !pSMBFile->invalidHandle)
667 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000669 } else
670 write_unlock(&GlobalSMBSeslock);
671 } else
672 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000673
674 /* Delete any outstanding lock records.
675 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000676 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000677 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
678 list_del(&li->llist);
679 kfree(li);
680 }
Roland Dreier796e5662007-05-03 04:33:45 +0000681 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000682
Steve Frenchcbe04762005-04-28 22:41:05 -0700683 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 list_del(&pSMBFile->flist);
685 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700686 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000687 timeout = 10;
688 /* We waited above to give the SMBWrite a chance to issue
689 on the wire (so we do not get SMBWrite returning EBADF
690 if writepages is racing with close. Note that writepages
691 does not specify a file handle, so it is possible for a file
692 to be opened twice, and the application close the "wrong"
693 file handle - in these cases we delay long enough to allow
694 the SMBWrite to get on the wire before the SMB Close.
695 We allow total wait here over 45 seconds, more than
696 oplock break time, and more than enough to allow any write
697 to complete on the server, or to time out on the client */
698 while ((atomic_read(&pSMBFile->wrtPending) != 0)
699 && (timeout <= 50000)) {
700 cERROR(1, ("writes pending, delay free of handle"));
701 msleep(timeout);
702 timeout *= 8;
703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 kfree(file->private_data);
705 file->private_data = NULL;
706 } else
707 rc = -EBADF;
708
Steve French4efa53f2007-09-11 05:50:53 +0000709 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (list_empty(&(CIFS_I(inode)->openFileList))) {
711 cFYI(1, ("closing last open instance for inode %p", inode));
712 /* if the file is not open we do not know if we can cache info
713 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000714 CIFS_I(inode)->clientCanCacheRead = false;
715 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
Steve French4efa53f2007-09-11 05:50:53 +0000717 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000718 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 rc = CIFS_I(inode)->write_behind_rc;
720 FreeXid(xid);
721 return rc;
722}
723
724int cifs_closedir(struct inode *inode, struct file *file)
725{
726 int rc = 0;
727 int xid;
728 struct cifsFileInfo *pCFileStruct =
729 (struct cifsFileInfo *)file->private_data;
730 char *ptmp;
731
Steve French26a21b92006-05-31 18:05:34 +0000732 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 xid = GetXid();
735
736 if (pCFileStruct) {
737 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000738 struct cifs_sb_info *cifs_sb =
739 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 pTcon = cifs_sb->tcon;
742
743 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000744 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000745 if (!pCFileStruct->srch_inf.endOfSearch &&
746 !pCFileStruct->invalidHandle) {
747 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000748 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
750 cFYI(1, ("Closing uncompleted readdir with rc %d",
751 rc));
752 /* not much we can do if it fails anyway, ignore rc */
753 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000754 } else
755 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
757 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800758 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000760 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000761 cifs_small_buf_release(ptmp);
762 else
763 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 kfree(file->private_data);
766 file->private_data = NULL;
767 }
768 /* BB can we lock the filestruct while this is going on? */
769 FreeXid(xid);
770 return rc;
771}
772
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000773static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
774 __u64 offset, __u8 lockType)
775{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000776 struct cifsLockInfo *li =
777 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000778 if (li == NULL)
779 return -ENOMEM;
780 li->offset = offset;
781 li->length = len;
782 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000783 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000784 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000785 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000786 return 0;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
790{
791 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 __u32 numLock = 0;
793 __u32 numUnlock = 0;
794 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000795 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000797 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000798 __u16 netfid;
799 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000800 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 length = 1 + pfLock->fl_end - pfLock->fl_start;
803 rc = -EACCES;
804 xid = GetXid();
805
806 cFYI(1, ("Lock parm: 0x%x flockflags: "
807 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000808 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
809 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000812 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000814 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000816 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000817 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 if (pfLock->fl_flags & FL_ACCESS)
820 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000821 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (pfLock->fl_flags & FL_LEASE)
823 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000824 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
826 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
827
828 if (pfLock->fl_type == F_WRLCK) {
829 cFYI(1, ("F_WRLCK "));
830 numLock = 1;
831 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000832 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000834 /* Check if unlock includes more than
835 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000837 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 lockType |= LOCKING_ANDX_SHARED_LOCK;
839 numLock = 1;
840 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000841 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 numLock = 1;
843 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000844 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 lockType |= LOCKING_ANDX_SHARED_LOCK;
846 numLock = 1;
847 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000848 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800850 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000851 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853 if (file->private_data == NULL) {
854 FreeXid(xid);
855 return -EBADF;
856 }
Steve French08547b02006-02-28 22:39:25 +0000857 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Steve French13a6e422008-12-02 17:24:33 +0000859 if ((tcon->ses->capabilities & CAP_UNIX) &&
860 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000861 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000862 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000863 /* BB add code here to normalize offset and length to
864 account for negative length which we can not accept over the
865 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000867 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000868 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000869 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000870 posix_lock_type = CIFS_RDLCK;
871 else
872 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000873 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000874 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000875 posix_lock_type, wait_flag);
876 FreeXid(xid);
877 return rc;
878 }
879
880 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000881 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000882 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000884 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 pfLock->fl_start, 1 /* numUnlock */ ,
886 0 /* numLock */ , lockType,
887 0 /* wait flag */ );
888 pfLock->fl_type = F_UNLCK;
889 if (rc != 0)
890 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000891 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 rc = 0;
893
894 } else {
895 /* if rc == ERR_SHARING_VIOLATION ? */
896 rc = 0; /* do not change lock type to unlock
897 since range in use */
898 }
899
900 FreeXid(xid);
901 return rc;
902 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000903
904 if (!numLock && !numUnlock) {
905 /* if no lock or unlock then nothing
906 to do since we do not know what it is */
907 FreeXid(xid);
908 return -EOPNOTSUPP;
909 }
910
911 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000912 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000913 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000914 posix_lock_type = CIFS_RDLCK;
915 else
916 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000917
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000918 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000919 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000920
Steve French13a6e422008-12-02 17:24:33 +0000921 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000922 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000923 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000925 struct cifsFileInfo *fid =
926 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000927
928 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000929 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000930 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000931 0, numLock, lockType, wait_flag);
932
933 if (rc == 0) {
934 /* For Windows locks we must store them. */
935 rc = store_file_lock(fid, length,
936 pfLock->fl_start, lockType);
937 }
938 } else if (numUnlock) {
939 /* For each stored lock that this unlock overlaps
940 completely, unlock it. */
941 int stored_rc = 0;
942 struct cifsLockInfo *li, *tmp;
943
Steve French6b70c952006-09-21 07:35:29 +0000944 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000945 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000946 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
947 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000948 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000949 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000950 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000951 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000952 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000953 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000954 if (stored_rc)
955 rc = stored_rc;
956
957 list_del(&li->llist);
958 kfree(li);
959 }
960 }
Roland Dreier796e5662007-05-03 04:33:45 +0000961 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000962 }
963 }
964
Steve Frenchd634cc12005-08-26 14:42:59 -0500965 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 posix_lock_file_wait(file, pfLock);
967 FreeXid(xid);
968 return rc;
969}
970
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400971/*
972 * Set the timeout on write requests past EOF. For some servers (Windows)
973 * these calls can be very long.
974 *
975 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
976 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
977 * The 10M cutoff is totally arbitrary. A better scheme for this would be
978 * welcome if someone wants to suggest one.
979 *
980 * We may be able to do a better job with this if there were some way to
981 * declare that a file should be sparse.
982 */
983static int
984cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
985{
986 if (offset <= cifsi->server_eof)
987 return CIFS_STD_OP;
988 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
989 return CIFS_VLONG_OP;
990 else
991 return CIFS_LONG_OP;
992}
993
994/* update the file size (if needed) after a write */
995static void
996cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
997 unsigned int bytes_written)
998{
999 loff_t end_of_write = offset + bytes_written;
1000
1001 if (end_of_write > cifsi->server_eof)
1002 cifsi->server_eof = end_of_write;
1003}
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005ssize_t cifs_user_write(struct file *file, const char __user *write_data,
1006 size_t write_size, loff_t *poffset)
1007{
1008 int rc = 0;
1009 unsigned int bytes_written = 0;
1010 unsigned int total_written;
1011 struct cifs_sb_info *cifs_sb;
1012 struct cifsTconInfo *pTcon;
1013 int xid, long_op;
1014 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001015 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001017 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 pTcon = cifs_sb->tcon;
1020
1021 /* cFYI(1,
1022 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001023 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 if (file->private_data == NULL)
1026 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001027 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001028
Jeff Layton838726c2008-08-28 07:54:59 -04001029 rc = generic_write_checks(file, poffset, &write_size, 0);
1030 if (rc)
1031 return rc;
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001035 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 for (total_written = 0; write_size > total_written;
1037 total_written += bytes_written) {
1038 rc = -EAGAIN;
1039 while (rc == -EAGAIN) {
1040 if (file->private_data == NULL) {
1041 /* file has been closed on us */
1042 FreeXid(xid);
1043 /* if we have gotten here we have written some data
1044 and blocked, and the file has been freed on us while
1045 we blocked so return what we managed to write */
1046 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 if (open_file->closePend) {
1049 FreeXid(xid);
1050 if (total_written)
1051 return total_written;
1052 else
1053 return -EBADF;
1054 }
1055 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* we could deadlock if we called
1057 filemap_fdatawait from here so tell
1058 reopen_file not to flush data to server
1059 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001060 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 if (rc != 0)
1062 break;
1063 }
1064
1065 rc = CIFSSMBWrite(xid, pTcon,
1066 open_file->netfid,
1067 min_t(const int, cifs_sb->wsize,
1068 write_size - total_written),
1069 *poffset, &bytes_written,
1070 NULL, write_data + total_written, long_op);
1071 }
1072 if (rc || (bytes_written == 0)) {
1073 if (total_written)
1074 break;
1075 else {
1076 FreeXid(xid);
1077 return rc;
1078 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001079 } else {
1080 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001082 }
Steve French133672e2007-11-13 22:41:37 +00001083 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 15 seconds is plenty */
1085 }
1086
Steve Frencha4544342005-08-24 13:59:35 -07001087 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001090 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1091 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001092/* Do not update local mtime - server will set its actual value on write
1093 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001094 * current_fs_time(inode->i_sb);*/
1095 if (total_written > 0) {
1096 spin_lock(&inode->i_lock);
1097 if (*poffset > file->f_path.dentry->d_inode->i_size)
1098 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001100 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001102 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
1104 FreeXid(xid);
1105 return total_written;
1106}
1107
1108static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001109 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
1111 int rc = 0;
1112 unsigned int bytes_written = 0;
1113 unsigned int total_written;
1114 struct cifs_sb_info *cifs_sb;
1115 struct cifsTconInfo *pTcon;
1116 int xid, long_op;
1117 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001118 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001120 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 pTcon = cifs_sb->tcon;
1123
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001124 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001125 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 if (file->private_data == NULL)
1128 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001129 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001133 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 for (total_written = 0; write_size > total_written;
1135 total_written += bytes_written) {
1136 rc = -EAGAIN;
1137 while (rc == -EAGAIN) {
1138 if (file->private_data == NULL) {
1139 /* file has been closed on us */
1140 FreeXid(xid);
1141 /* if we have gotten here we have written some data
1142 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001143 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 write */
1145 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 if (open_file->closePend) {
1148 FreeXid(xid);
1149 if (total_written)
1150 return total_written;
1151 else
1152 return -EBADF;
1153 }
1154 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 /* we could deadlock if we called
1156 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001157 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001159 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (rc != 0)
1161 break;
1162 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001163 if (experimEnabled || (pTcon->ses->server &&
1164 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001165 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001166 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001167 struct kvec iov[2];
1168 unsigned int len;
1169
Steve French0ae0efa2005-10-10 10:57:19 -07001170 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001171 write_size - total_written);
1172 /* iov[0] is reserved for smb header */
1173 iov[1].iov_base = (char *)write_data +
1174 total_written;
1175 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001176 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001177 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001178 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001179 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001180 } else
Steve French60808232006-04-22 15:53:05 +00001181 rc = CIFSSMBWrite(xid, pTcon,
1182 open_file->netfid,
1183 min_t(const int, cifs_sb->wsize,
1184 write_size - total_written),
1185 *poffset, &bytes_written,
1186 write_data + total_written,
1187 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189 if (rc || (bytes_written == 0)) {
1190 if (total_written)
1191 break;
1192 else {
1193 FreeXid(xid);
1194 return rc;
1195 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001196 } else {
1197 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001199 }
Steve French133672e2007-11-13 22:41:37 +00001200 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 15 seconds is plenty */
1202 }
1203
Steve Frencha4544342005-08-24 13:59:35 -07001204 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
1206 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001207 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001208/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001209/* file->f_path.dentry->d_inode->i_ctime =
1210 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1211 if (total_written > 0) {
1212 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1213 if (*poffset > file->f_path.dentry->d_inode->i_size)
1214 i_size_write(file->f_path.dentry->d_inode,
1215 *poffset);
1216 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
Steve French3677db12007-02-26 16:46:11 +00001218 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220 FreeXid(xid);
1221 return total_written;
1222}
1223
Steve French630f3f0c2007-10-25 21:17:17 +00001224#ifdef CONFIG_CIFS_EXPERIMENTAL
1225struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1226{
1227 struct cifsFileInfo *open_file = NULL;
1228
1229 read_lock(&GlobalSMBSeslock);
1230 /* we could simply get the first_list_entry since write-only entries
1231 are always at the end of the list but since the first entry might
1232 have a close pending, we go through the whole list */
1233 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1234 if (open_file->closePend)
1235 continue;
1236 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1237 (open_file->pfile->f_flags & O_RDONLY))) {
1238 if (!open_file->invalidHandle) {
1239 /* found a good file */
1240 /* lock it so it will not be closed on us */
1241 atomic_inc(&open_file->wrtPending);
1242 read_unlock(&GlobalSMBSeslock);
1243 return open_file;
1244 } /* else might as well continue, and look for
1245 another, or simply have the caller reopen it
1246 again rather than trying to fix this handle */
1247 } else /* write only file */
1248 break; /* write only files are last so must be done */
1249 }
1250 read_unlock(&GlobalSMBSeslock);
1251 return NULL;
1252}
1253#endif
1254
Steve Frenchdd99cd82005-10-05 19:32:49 -07001255struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001256{
1257 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001258 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001259 int rc;
Steve French6148a742005-10-05 12:23:19 -07001260
Steve French60808232006-04-22 15:53:05 +00001261 /* Having a null inode here (because mapping->host was set to zero by
1262 the VFS or MM) should not happen but we had reports of on oops (due to
1263 it being zero) during stress testcases so we need to check for it */
1264
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001265 if (cifs_inode == NULL) {
1266 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001267 dump_stack();
1268 return NULL;
1269 }
1270
Steve French6148a742005-10-05 12:23:19 -07001271 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001272refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001273 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001274 if (open_file->closePend ||
1275 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001276 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001277
Steve French6148a742005-10-05 12:23:19 -07001278 if (open_file->pfile &&
1279 ((open_file->pfile->f_flags & O_RDWR) ||
1280 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001281 atomic_inc(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001282
1283 if (!open_file->invalidHandle) {
1284 /* found a good writable file */
1285 read_unlock(&GlobalSMBSeslock);
1286 return open_file;
1287 }
Steve French8840dee2007-11-16 23:05:52 +00001288
Steve French6148a742005-10-05 12:23:19 -07001289 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001290 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001291 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001292 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001293 if (!open_file->closePend)
1294 return open_file;
1295 else { /* start over in case this was deleted */
1296 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001297 read_lock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +00001298 atomic_dec(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001299 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001300 }
1301 }
Steve French9b22b0b2007-10-02 01:11:08 +00001302
1303 /* if it fails, try another handle if possible -
1304 (we can not do this if closePending since
1305 loop could be modified - in which case we
1306 have to start at the beginning of the list
1307 again. Note that it would be bad
1308 to hold up writepages here (rather than
1309 in caller) with continuous retries */
1310 cFYI(1, ("wp failed on reopen file"));
1311 read_lock(&GlobalSMBSeslock);
1312 /* can not use this handle, no write
1313 pending on this one after all */
1314 atomic_dec(&open_file->wrtPending);
Steve French8840dee2007-11-16 23:05:52 +00001315
Steve French9b22b0b2007-10-02 01:11:08 +00001316 if (open_file->closePend) /* list could have changed */
1317 goto refind_writable;
1318 /* else we simply continue to the next entry. Thus
1319 we do not loop on reopen errors. If we
1320 can not reopen the file, for example if we
1321 reconnected to a server with another client
1322 racing to delete or lock the file we would not
1323 make progress if we restarted before the beginning
1324 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001325 }
1326 }
Jeff Layton2846d382008-09-22 21:33:33 -04001327 /* couldn't find useable FH with same pid, try any available */
1328 if (!any_available) {
1329 any_available = true;
1330 goto refind_writable;
1331 }
Steve French6148a742005-10-05 12:23:19 -07001332 read_unlock(&GlobalSMBSeslock);
1333 return NULL;
1334}
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1337{
1338 struct address_space *mapping = page->mapping;
1339 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1340 char *write_data;
1341 int rc = -EFAULT;
1342 int bytes_written = 0;
1343 struct cifs_sb_info *cifs_sb;
1344 struct cifsTconInfo *pTcon;
1345 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001346 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 if (!mapping || !mapping->host)
1349 return -EFAULT;
1350
1351 inode = page->mapping->host;
1352 cifs_sb = CIFS_SB(inode->i_sb);
1353 pTcon = cifs_sb->tcon;
1354
1355 offset += (loff_t)from;
1356 write_data = kmap(page);
1357 write_data += from;
1358
1359 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1360 kunmap(page);
1361 return -EIO;
1362 }
1363
1364 /* racing with truncate? */
1365 if (offset > mapping->host->i_size) {
1366 kunmap(page);
1367 return 0; /* don't care */
1368 }
1369
1370 /* check to make sure that we are not extending the file */
1371 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001372 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Steve French6148a742005-10-05 12:23:19 -07001374 open_file = find_writable_file(CIFS_I(mapping->host));
1375 if (open_file) {
1376 bytes_written = cifs_write(open_file->pfile, write_data,
1377 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001378 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001380 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001381 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001382 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001383 else if (bytes_written < 0)
1384 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001385 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 cFYI(1, ("No writeable filehandles for inode"));
1387 rc = -EIO;
1388 }
1389
1390 kunmap(page);
1391 return rc;
1392}
1393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001395 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396{
Steve French37c0eb42005-10-05 14:50:29 -07001397 struct backing_dev_info *bdi = mapping->backing_dev_info;
1398 unsigned int bytes_to_write;
1399 unsigned int bytes_written;
1400 struct cifs_sb_info *cifs_sb;
1401 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001402 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001403 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001404 int range_whole = 0;
1405 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001406 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001407 int n_iov = 0;
1408 pgoff_t next;
1409 int nr_pages;
1410 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001411 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001412 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001413 struct page *page;
1414 struct pagevec pvec;
1415 int rc = 0;
1416 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001417 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Steve French37c0eb42005-10-05 14:50:29 -07001419 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001420
Steve French37c0eb42005-10-05 14:50:29 -07001421 /*
1422 * If wsize is smaller that the page cache size, default to writing
1423 * one page at a time via cifs_writepage
1424 */
1425 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1426 return generic_writepages(mapping, wbc);
1427
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001428 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1429 if (cifs_sb->tcon->ses->server->secMode &
1430 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1431 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001432 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001433
Steve French9a0c8232007-02-02 04:21:57 +00001434 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001435 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001436 return generic_writepages(mapping, wbc);
1437
1438
Steve French37c0eb42005-10-05 14:50:29 -07001439 /*
1440 * BB: Is this meaningful for a non-block-device file system?
1441 * If it is, we should test it again after we do I/O
1442 */
1443 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1444 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001445 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001446 return 0;
1447 }
1448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 xid = GetXid();
1450
Steve French37c0eb42005-10-05 14:50:29 -07001451 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001452 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001453 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001454 end = -1;
1455 } else {
1456 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1457 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1458 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1459 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001460 scanned = 1;
1461 }
1462retry:
1463 while (!done && (index <= end) &&
1464 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1465 PAGECACHE_TAG_DIRTY,
1466 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1467 int first;
1468 unsigned int i;
1469
Steve French37c0eb42005-10-05 14:50:29 -07001470 first = -1;
1471 next = 0;
1472 n_iov = 0;
1473 bytes_to_write = 0;
1474
1475 for (i = 0; i < nr_pages; i++) {
1476 page = pvec.pages[i];
1477 /*
1478 * At this point we hold neither mapping->tree_lock nor
1479 * lock on the page itself: the page may be truncated or
1480 * invalidated (changing page->mapping to NULL), or even
1481 * swizzled back from swapper_space to tmpfs file
1482 * mapping
1483 */
1484
1485 if (first < 0)
1486 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001487 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001488 break;
1489
1490 if (unlikely(page->mapping != mapping)) {
1491 unlock_page(page);
1492 break;
1493 }
1494
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001495 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001496 done = 1;
1497 unlock_page(page);
1498 break;
1499 }
1500
1501 if (next && (page->index != next)) {
1502 /* Not next consecutive page */
1503 unlock_page(page);
1504 break;
1505 }
1506
1507 if (wbc->sync_mode != WB_SYNC_NONE)
1508 wait_on_page_writeback(page);
1509
1510 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001511 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001512 unlock_page(page);
1513 break;
1514 }
Steve French84d2f072005-10-12 15:32:05 -07001515
Linus Torvaldscb876f42006-12-23 16:19:07 -08001516 /*
1517 * This actually clears the dirty bit in the radix tree.
1518 * See cifs_writepage() for more commentary.
1519 */
1520 set_page_writeback(page);
1521
Steve French84d2f072005-10-12 15:32:05 -07001522 if (page_offset(page) >= mapping->host->i_size) {
1523 done = 1;
1524 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001525 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001526 break;
1527 }
1528
Steve French37c0eb42005-10-05 14:50:29 -07001529 /*
1530 * BB can we get rid of this? pages are held by pvec
1531 */
1532 page_cache_get(page);
1533
Steve French84d2f072005-10-12 15:32:05 -07001534 len = min(mapping->host->i_size - page_offset(page),
1535 (loff_t)PAGE_CACHE_SIZE);
1536
Steve French37c0eb42005-10-05 14:50:29 -07001537 /* reserve iov[0] for the smb header */
1538 n_iov++;
1539 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001540 iov[n_iov].iov_len = len;
1541 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001542
1543 if (first < 0) {
1544 first = i;
1545 offset = page_offset(page);
1546 }
1547 next = page->index + 1;
1548 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1549 break;
1550 }
1551 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001552 /* Search for a writable handle every time we call
1553 * CIFSSMBWrite2. We can't rely on the last handle
1554 * we used to still be valid
1555 */
1556 open_file = find_writable_file(CIFS_I(mapping->host));
1557 if (!open_file) {
1558 cERROR(1, ("No writable handles for inode"));
1559 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001560 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001561 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001562 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1563 open_file->netfid,
1564 bytes_to_write, offset,
1565 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001566 long_op);
Steve French23e7dd72005-10-20 13:44:56 -07001567 atomic_dec(&open_file->wrtPending);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001568 cifs_update_eof(cifsi, offset, bytes_written);
1569
Steve French23e7dd72005-10-20 13:44:56 -07001570 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001571 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001572 rc, bytes_written));
1573 /* BB what if continued retry is
1574 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001575 if (rc == -ENOSPC)
1576 set_bit(AS_ENOSPC, &mapping->flags);
1577 else
1578 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001579 } else {
1580 cifs_stats_bytes_written(cifs_sb->tcon,
1581 bytes_written);
1582 }
Steve French37c0eb42005-10-05 14:50:29 -07001583 }
1584 for (i = 0; i < n_iov; i++) {
1585 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001586 /* Should we also set page error on
1587 success rc but too little data written? */
1588 /* BB investigate retry logic on temporary
1589 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001590 when page marked as error */
1591 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001592 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001593 kunmap(page);
1594 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001595 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001596 page_cache_release(page);
1597 }
1598 if ((wbc->nr_to_write -= n_iov) <= 0)
1599 done = 1;
1600 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001601 } else
1602 /* Need to re-find the pages we skipped */
1603 index = pvec.pages[0]->index + 1;
1604
Steve French37c0eb42005-10-05 14:50:29 -07001605 pagevec_release(&pvec);
1606 }
1607 if (!scanned && !done) {
1608 /*
1609 * We hit the last page and there is more work to be done: wrap
1610 * back to the start of the file
1611 */
1612 scanned = 1;
1613 index = 0;
1614 goto retry;
1615 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001616 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001617 mapping->writeback_index = index;
1618
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001620 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 return rc;
1622}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001624static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625{
1626 int rc = -EFAULT;
1627 int xid;
1628
1629 xid = GetXid();
1630/* BB add check for wbc flags */
1631 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001632 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001634
1635 /*
1636 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1637 *
1638 * A writepage() implementation always needs to do either this,
1639 * or re-dirty the page with "redirty_page_for_writepage()" in
1640 * the case of a failure.
1641 *
1642 * Just unlocking the page will cause the radix tree tag-bits
1643 * to fail to update with the state of the page correctly.
1644 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001645 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1647 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1648 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001649 end_page_writeback(page);
1650 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 FreeXid(xid);
1652 return rc;
1653}
1654
Nick Piggind9414772008-09-24 11:32:59 -04001655static int cifs_write_end(struct file *file, struct address_space *mapping,
1656 loff_t pos, unsigned len, unsigned copied,
1657 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658{
Nick Piggind9414772008-09-24 11:32:59 -04001659 int rc;
1660 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Nick Piggind9414772008-09-24 11:32:59 -04001662 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1663 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001664
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001665 if (PageChecked(page)) {
1666 if (copied == len)
1667 SetPageUptodate(page);
1668 ClearPageChecked(page);
1669 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001670 SetPageUptodate(page);
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001673 char *page_data;
1674 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1675 int xid;
1676
1677 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 /* this is probably better than directly calling
1679 partialpage_write since in this function the file handle is
1680 known which we might as well leverage */
1681 /* BB check if anything else missing out of ppw
1682 such as updating last write time */
1683 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001684 rc = cifs_write(file, page_data + offset, copied, &pos);
1685 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001687
1688 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001689 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001690 rc = copied;
1691 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 set_page_dirty(page);
1693 }
1694
Nick Piggind9414772008-09-24 11:32:59 -04001695 if (rc > 0) {
1696 spin_lock(&inode->i_lock);
1697 if (pos > inode->i_size)
1698 i_size_write(inode, pos);
1699 spin_unlock(&inode->i_lock);
1700 }
1701
1702 unlock_page(page);
1703 page_cache_release(page);
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return rc;
1706}
1707
1708int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1709{
1710 int xid;
1711 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001712 struct cifsTconInfo *tcon;
1713 struct cifsFileInfo *smbfile =
1714 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001715 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717 xid = GetXid();
1718
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001719 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001721
Jeff Laytoncea21802007-11-20 23:19:03 +00001722 rc = filemap_write_and_wait(inode->i_mapping);
1723 if (rc == 0) {
1724 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001726 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001727 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001728 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001729 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001730 }
Steve Frenchb298f222009-02-21 21:17:43 +00001731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 FreeXid(xid);
1733 return rc;
1734}
1735
NeilBrown3978d712006-03-26 01:37:17 -08001736/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737{
1738 struct address_space *mapping;
1739 struct inode *inode;
1740 unsigned long index = page->index;
1741 unsigned int rpages = 0;
1742 int rc = 0;
1743
1744 cFYI(1, ("sync page %p",page));
1745 mapping = page->mapping;
1746 if (!mapping)
1747 return 0;
1748 inode = mapping->host;
1749 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001750 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001752/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1754
Steve French26a21b92006-05-31 18:05:34 +00001755/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
NeilBrown3978d712006-03-26 01:37:17 -08001757#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc < 0)
1759 return rc;
1760 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001761#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762} */
1763
1764/*
1765 * As file closes, flush all cached write data for this inode checking
1766 * for write behind errors.
1767 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001768int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001770 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 int rc = 0;
1772
1773 /* Rather than do the steps manually:
1774 lock the inode for writing
1775 loop through pages looking for write behind data (dirty pages)
1776 coalesce into contiguous 16K (or smaller) chunks to write to server
1777 send to server (prefer in parallel)
1778 deal with writebehind errors
1779 unlock inode for writing
1780 filemapfdatawrite appears easier for the time being */
1781
1782 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001783 /* reset wb rc if we were able to write out dirty pages */
1784 if (!rc) {
1785 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001787 }
Steve French50c2f752007-07-13 00:33:32 +00001788
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 return rc;
1792}
1793
1794ssize_t cifs_user_read(struct file *file, char __user *read_data,
1795 size_t read_size, loff_t *poffset)
1796{
1797 int rc = -EACCES;
1798 unsigned int bytes_read = 0;
1799 unsigned int total_read = 0;
1800 unsigned int current_read_size;
1801 struct cifs_sb_info *cifs_sb;
1802 struct cifsTconInfo *pTcon;
1803 int xid;
1804 struct cifsFileInfo *open_file;
1805 char *smb_read_data;
1806 char __user *current_offset;
1807 struct smb_com_read_rsp *pSMBr;
1808
1809 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001810 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 pTcon = cifs_sb->tcon;
1812
1813 if (file->private_data == NULL) {
1814 FreeXid(xid);
1815 return -EBADF;
1816 }
1817 open_file = (struct cifsFileInfo *)file->private_data;
1818
Steve Frenchad7a2922008-02-07 23:25:02 +00001819 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 for (total_read = 0, current_offset = read_data;
1823 read_size > total_read;
1824 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001825 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 cifs_sb->rsize);
1827 rc = -EAGAIN;
1828 smb_read_data = NULL;
1829 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001830 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001831 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001833 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (rc != 0)
1835 break;
1836 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001837 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001838 open_file->netfid,
1839 current_read_size, *poffset,
1840 &bytes_read, &smb_read_data,
1841 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001844 if (copy_to_user(current_offset,
1845 smb_read_data +
1846 4 /* RFC1001 length field */ +
1847 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001848 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001849 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001850
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001851 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001852 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001853 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001854 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 smb_read_data = NULL;
1856 }
1857 }
1858 if (rc || (bytes_read == 0)) {
1859 if (total_read) {
1860 break;
1861 } else {
1862 FreeXid(xid);
1863 return rc;
1864 }
1865 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001866 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 *poffset += bytes_read;
1868 }
1869 }
1870 FreeXid(xid);
1871 return total_read;
1872}
1873
1874
1875static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1876 loff_t *poffset)
1877{
1878 int rc = -EACCES;
1879 unsigned int bytes_read = 0;
1880 unsigned int total_read;
1881 unsigned int current_read_size;
1882 struct cifs_sb_info *cifs_sb;
1883 struct cifsTconInfo *pTcon;
1884 int xid;
1885 char *current_offset;
1886 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001887 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001890 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 pTcon = cifs_sb->tcon;
1892
1893 if (file->private_data == NULL) {
1894 FreeXid(xid);
1895 return -EBADF;
1896 }
1897 open_file = (struct cifsFileInfo *)file->private_data;
1898
1899 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1900 cFYI(1, ("attempting read on write only file instance"));
1901
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 read_size > total_read;
1904 total_read += bytes_read, current_offset += bytes_read) {
1905 current_read_size = min_t(const int, read_size - total_read,
1906 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001907 /* For windows me and 9x we do not want to request more
1908 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001909 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001910 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1911 current_read_size = min_t(const int, current_read_size,
1912 pTcon->ses->server->maxBuf - 128);
1913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 rc = -EAGAIN;
1915 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001916 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001918 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 if (rc != 0)
1920 break;
1921 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001922 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001923 open_file->netfid,
1924 current_read_size, *poffset,
1925 &bytes_read, &current_offset,
1926 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 }
1928 if (rc || (bytes_read == 0)) {
1929 if (total_read) {
1930 break;
1931 } else {
1932 FreeXid(xid);
1933 return rc;
1934 }
1935 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001936 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 *poffset += bytes_read;
1938 }
1939 }
1940 FreeXid(xid);
1941 return total_read;
1942}
1943
1944int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1945{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001946 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 int rc, xid;
1948
1949 xid = GetXid();
1950 rc = cifs_revalidate(dentry);
1951 if (rc) {
1952 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1953 FreeXid(xid);
1954 return rc;
1955 }
1956 rc = generic_file_mmap(file, vma);
1957 FreeXid(xid);
1958 return rc;
1959}
1960
1961
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001962static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 struct list_head *pages, int bytes_read, char *data,
1964 struct pagevec *plru_pvec)
1965{
1966 struct page *page;
1967 char *target;
1968
1969 while (bytes_read > 0) {
1970 if (list_empty(pages))
1971 break;
1972
1973 page = list_entry(pages->prev, struct page, lru);
1974 list_del(&page->lru);
1975
1976 if (add_to_page_cache(page, mapping, page->index,
1977 GFP_KERNEL)) {
1978 page_cache_release(page);
1979 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001980 data += PAGE_CACHE_SIZE;
1981 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 continue;
1983 }
1984
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001985 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 if (PAGE_CACHE_SIZE > bytes_read) {
1988 memcpy(target, data, bytes_read);
1989 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001990 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 PAGE_CACHE_SIZE - bytes_read);
1992 bytes_read = 0;
1993 } else {
1994 memcpy(target, data, PAGE_CACHE_SIZE);
1995 bytes_read -= PAGE_CACHE_SIZE;
1996 }
1997 kunmap_atomic(target, KM_USER0);
1998
1999 flush_dcache_page(page);
2000 SetPageUptodate(page);
2001 unlock_page(page);
2002 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002003 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 data += PAGE_CACHE_SIZE;
2005 }
2006 return;
2007}
2008
2009static int cifs_readpages(struct file *file, struct address_space *mapping,
2010 struct list_head *page_list, unsigned num_pages)
2011{
2012 int rc = -EACCES;
2013 int xid;
2014 loff_t offset;
2015 struct page *page;
2016 struct cifs_sb_info *cifs_sb;
2017 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00002018 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002019 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 char *smb_read_data = NULL;
2021 struct smb_com_read_rsp *pSMBr;
2022 struct pagevec lru_pvec;
2023 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002024 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 xid = GetXid();
2027 if (file->private_data == NULL) {
2028 FreeXid(xid);
2029 return -EBADF;
2030 }
2031 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002032 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00002036 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 for (i = 0; i < num_pages; ) {
2038 unsigned contig_pages;
2039 struct page *tmp_page;
2040 unsigned long expected_index;
2041
2042 if (list_empty(page_list))
2043 break;
2044
2045 page = list_entry(page_list->prev, struct page, lru);
2046 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2047
2048 /* count adjacent pages that we will read into */
2049 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002050 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 if (tmp_page->index == expected_index) {
2054 contig_pages++;
2055 expected_index++;
2056 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 }
2059 if (contig_pages + i > num_pages)
2060 contig_pages = num_pages - i;
2061
2062 /* for reads over a certain size could initiate async
2063 read ahead */
2064
2065 read_size = contig_pages * PAGE_CACHE_SIZE;
2066 /* Read size needs to be in multiples of one page */
2067 read_size = min_t(const unsigned int, read_size,
2068 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002069 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002070 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 rc = -EAGAIN;
2072 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002073 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002075 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 if (rc != 0)
2077 break;
2078 }
2079
Steve Frenchbfa0d752005-08-31 21:50:37 -07002080 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002081 open_file->netfid,
2082 read_size, offset,
2083 &bytes_read, &smb_read_data,
2084 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002085 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002086 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002088 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002089 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002091 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 smb_read_data = NULL;
2093 }
2094 }
2095 }
2096 if ((rc < 0) || (smb_read_data == NULL)) {
2097 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 break;
2099 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002100 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2102 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2103 smb_read_data + 4 /* RFC1001 hdr */ +
2104 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2105
2106 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002107 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002108 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 i++; /* account for partial page */
2110
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002111 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002113 /* BB do we need to verify this common case ?
2114 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 we will hit it on next read */
2116
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002117 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 }
2119 } else {
2120 cFYI(1, ("No bytes read (%d) at offset %lld . "
2121 "Cleaning remaining pages from readahead list",
2122 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002123 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 break;
2126 }
2127 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002129 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002130 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002131 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 smb_read_data = NULL;
2133 }
2134 bytes_read = 0;
2135 }
2136
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002137 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
2139/* need to free smb_read_data buf before exit */
2140 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002141 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002142 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002143 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002144 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
2148 FreeXid(xid);
2149 return rc;
2150}
2151
2152static int cifs_readpage_worker(struct file *file, struct page *page,
2153 loff_t *poffset)
2154{
2155 char *read_data;
2156 int rc;
2157
2158 page_cache_get(page);
2159 read_data = kmap(page);
2160 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (rc < 0)
2165 goto io_error;
2166 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002167 cFYI(1, ("Bytes read %d", rc));
2168
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002169 file->f_path.dentry->d_inode->i_atime =
2170 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002171
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (PAGE_CACHE_SIZE > rc)
2173 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2174
2175 flush_dcache_page(page);
2176 SetPageUptodate(page);
2177 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002180 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 page_cache_release(page);
2182 return rc;
2183}
2184
2185static int cifs_readpage(struct file *file, struct page *page)
2186{
2187 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2188 int rc = -EACCES;
2189 int xid;
2190
2191 xid = GetXid();
2192
2193 if (file->private_data == NULL) {
2194 FreeXid(xid);
2195 return -EBADF;
2196 }
2197
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002198 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 page, (int)offset, (int)offset));
2200
2201 rc = cifs_readpage_worker(file, page, &offset);
2202
2203 unlock_page(page);
2204
2205 FreeXid(xid);
2206 return rc;
2207}
2208
Steve Frencha403a0a2007-07-26 15:54:16 +00002209static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2210{
2211 struct cifsFileInfo *open_file;
2212
2213 read_lock(&GlobalSMBSeslock);
2214 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2215 if (open_file->closePend)
2216 continue;
2217 if (open_file->pfile &&
2218 ((open_file->pfile->f_flags & O_RDWR) ||
2219 (open_file->pfile->f_flags & O_WRONLY))) {
2220 read_unlock(&GlobalSMBSeslock);
2221 return 1;
2222 }
2223 }
2224 read_unlock(&GlobalSMBSeslock);
2225 return 0;
2226}
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228/* We do not want to update the file size from server for inodes
2229 open for write - to avoid races with writepage extending
2230 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002231 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 but this is tricky to do without racing with writebehind
2233 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002234bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235{
Steve Frencha403a0a2007-07-26 15:54:16 +00002236 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002237 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002238
Steve Frencha403a0a2007-07-26 15:54:16 +00002239 if (is_inode_writable(cifsInode)) {
2240 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002241 struct cifs_sb_info *cifs_sb;
2242
Steve Frenchc32a0b62006-01-12 14:41:28 -08002243 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002244 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002245 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002246 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002247 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002248 }
2249
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002250 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002251 return true;
Steve French7ba526312007-02-08 18:14:13 +00002252
Steve French4b18f2a2008-04-29 00:06:05 +00002253 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002254 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002255 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256}
2257
Nick Piggind9414772008-09-24 11:32:59 -04002258static int cifs_write_begin(struct file *file, struct address_space *mapping,
2259 loff_t pos, unsigned len, unsigned flags,
2260 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
Nick Piggind9414772008-09-24 11:32:59 -04002262 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2263 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002264 loff_t page_start = pos & PAGE_MASK;
2265 loff_t i_size;
2266 struct page *page;
2267 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Nick Piggind9414772008-09-24 11:32:59 -04002269 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2270
Nick Piggin54566b22009-01-04 12:00:53 -08002271 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002272 if (!page) {
2273 rc = -ENOMEM;
2274 goto out;
2275 }
Nick Piggind9414772008-09-24 11:32:59 -04002276
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002277 if (PageUptodate(page))
2278 goto out;
Steve French8a236262007-03-06 00:31:00 +00002279
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002280 /*
2281 * If we write a full page it will be up to date, no need to read from
2282 * the server. If the write is short, we'll end up doing a sync write
2283 * instead.
2284 */
2285 if (len == PAGE_CACHE_SIZE)
2286 goto out;
2287
2288 /*
2289 * optimize away the read when we have an oplock, and we're not
2290 * expecting to use any of the data we'd be reading in. That
2291 * is, when the page lies beyond the EOF, or straddles the EOF
2292 * and the write will cover all of the existing data.
2293 */
2294 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2295 i_size = i_size_read(mapping->host);
2296 if (page_start >= i_size ||
2297 (offset == 0 && (pos + len) >= i_size)) {
2298 zero_user_segments(page, 0, offset,
2299 offset + len,
2300 PAGE_CACHE_SIZE);
2301 /*
2302 * PageChecked means that the parts of the page
2303 * to which we're not writing are considered up
2304 * to date. Once the data is copied to the
2305 * page, it can be set uptodate.
2306 */
2307 SetPageChecked(page);
2308 goto out;
2309 }
2310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Nick Piggind9414772008-09-24 11:32:59 -04002312 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002313 /*
2314 * might as well read a page, it is fast enough. If we get
2315 * an error, we don't need to return it. cifs_write_end will
2316 * do a sync write instead since PG_uptodate isn't set.
2317 */
2318 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002319 } else {
2320 /* we could try using another file handle if there is one -
2321 but how would we lock it to prevent close of that handle
2322 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002323 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002324 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002325out:
2326 *pagep = page;
2327 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328}
2329
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002330const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 .readpage = cifs_readpage,
2332 .readpages = cifs_readpages,
2333 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002334 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002335 .write_begin = cifs_write_begin,
2336 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 .set_page_dirty = __set_page_dirty_nobuffers,
2338 /* .sync_page = cifs_sync_page, */
2339 /* .direct_IO = */
2340};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002341
2342/*
2343 * cifs_readpages requires the server to support a buffer large enough to
2344 * contain the header plus one complete page of data. Otherwise, we need
2345 * to leave cifs_readpages out of the address space operations.
2346 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002347const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002348 .readpage = cifs_readpage,
2349 .writepage = cifs_writepage,
2350 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002351 .write_begin = cifs_write_begin,
2352 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002353 .set_page_dirty = __set_page_dirty_nobuffers,
2354 /* .sync_page = cifs_sync_page, */
2355 /* .direct_IO = */
2356};