blob: 48c9ae09f3d6e6afa13a8a08b10eec04372017d8 [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;
310 } else {
311 if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
312 cERROR(1, ("could not find file instance for "
313 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
315
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800316 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (full_path == NULL) {
318 FreeXid(xid);
319 return -ENOMEM;
320 }
321
Steve French7521a3c2007-07-11 18:30:34 +0000322 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000324
325 if (oplockEnabled)
326 oplock = REQ_OPLOCK;
327 else
328 oplock = 0;
329
Steve French64cc2c62009-03-04 19:54:08 +0000330 if (!tcon->broken_posix_open && tcon->unix_ext &&
331 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000332 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
333 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
334 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
335 /* can not refresh inode info since size could be stale */
336 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
337 cifs_sb->mnt_file_mode /* ignored */,
338 oflags, &oplock, &netfid, xid);
339 if (rc == 0) {
340 cFYI(1, ("posix open succeeded"));
341 /* no need for special case handling of setting mode
342 on read only files needed here */
343
344 cifs_posix_open_inode_helper(inode, file, pCifsInode,
345 pCifsFile, oplock, netfid);
346 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000347 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
348 if (tcon->ses->serverNOS)
349 cERROR(1, ("server %s of type %s returned"
350 " unexpected error on SMB posix open"
351 ", disabling posix open support."
352 " Check if server update available.",
353 tcon->ses->serverName,
354 tcon->ses->serverNOS));
355 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000356 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
357 (rc != -EOPNOTSUPP)) /* path not found or net err */
358 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000359 /* else fallthrough to retry open the old way on network i/o
360 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000361 }
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 desiredAccess = cifs_convert_flags(file->f_flags);
364
365/*********************************************************************
366 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000369 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 * O_CREAT FILE_OPEN_IF
371 * O_CREAT | O_EXCL FILE_CREATE
372 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
373 * O_TRUNC FILE_OVERWRITE
374 * none of the above FILE_OPEN
375 *
376 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000377 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 * O_CREAT | O_TRUNC is similar but truncates the existing
379 * file rather than creating a new file as FILE_SUPERSEDE does
380 * (which uses the attributes / metadata passed in on open call)
381 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000382 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 *? and the read write flags match reasonably. O_LARGEFILE
384 *? is irrelevant because largefile support is always used
385 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
386 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
387 *********************************************************************/
388
389 disposition = cifs_get_disposition(file->f_flags);
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BB pass O_SYNC flag through on file attributes .. BB */
392
393 /* Also refresh inode by passing in file_info buf returned by SMBOpen
394 and calling get_inode_info with returned buf (at least helps
395 non-Unix server case) */
396
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000397 /* BB we can not do this if this is the second open of a file
398 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
400 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
401 if (!buf) {
402 rc = -ENOMEM;
403 goto out;
404 }
Steve French5bafd762006-06-07 00:18:43 +0000405
406 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000407 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000408 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700409 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
410 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000411 else
412 rc = -EIO; /* no NT SMB support fall into legacy open below */
413
Steve Frencha9d02ad2005-08-24 23:06:05 -0700414 if (rc == -EIO) {
415 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000416 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700417 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
418 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
419 & CIFS_MOUNT_MAP_SPECIAL_CHR);
420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000422 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 goto out;
424 }
425 file->private_data =
426 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
427 if (file->private_data == NULL) {
428 rc = -ENOMEM;
429 goto out;
430 }
431 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000433 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800435 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (pCifsInode) {
437 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000438 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 &oplock, buf, full_path, xid);
440 } else {
441 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 }
443
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000444 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 /* time to set mode which we can not set earlier due to
446 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000447 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400448 struct cifs_unix_set_info_args args = {
449 .mode = inode->i_mode,
450 .uid = NO_CHANGE_64,
451 .gid = NO_CHANGE_64,
452 .ctime = NO_CHANGE_64,
453 .atime = NO_CHANGE_64,
454 .mtime = NO_CHANGE_64,
455 .device = 0,
456 };
Steve French276a74a2009-03-03 18:00:34 +0000457 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
Steve French737b7582005-04-28 22:41:06 -0700458 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700460 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462 }
463
464out:
465 kfree(buf);
466 kfree(full_path);
467 FreeXid(xid);
468 return rc;
469}
470
Adrian Bunk04187262006-06-30 18:23:04 +0200471/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472/* to server was lost */
473static int cifs_relock_file(struct cifsFileInfo *cifsFile)
474{
475 int rc = 0;
476
477/* BB list all locks open on this file and relock */
478
479 return rc;
480}
481
Steve French4b18f2a2008-04-29 00:06:05 +0000482static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
484 int rc = -EACCES;
485 int xid, oplock;
486 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000487 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 struct cifsFileInfo *pCifsFile;
489 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000490 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 char *full_path = NULL;
492 int desiredAccess;
493 int disposition = FILE_OPEN;
494 __u16 netfid;
495
Steve Frenchad7a2922008-02-07 23:25:02 +0000496 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000498 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return -EBADF;
500
501 xid = GetXid();
Steve Frencha6ce4932009-04-09 01:14:32 +0000502 mutex_unlock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000503 if (!pCifsFile->invalidHandle) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000504 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 FreeXid(xid);
506 return 0;
507 }
508
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800509 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000510 cERROR(1, ("no valid name if dentry freed"));
511 dump_stack();
512 rc = -EBADF;
513 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
Steve French3a9f4622007-04-04 17:10:24 +0000515
516 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000517 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000518 cERROR(1, ("inode not valid"));
519 dump_stack();
520 rc = -EBADF;
521 goto reopen_error_exit;
522 }
Steve French50c2f752007-07-13 00:33:32 +0000523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000525 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527/* can not grab rename sem here because various ops, including
528 those that already have the rename sem can end up causing writepage
529 to get called and if the server was down that means we end up here,
530 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800531 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000533 rc = -ENOMEM;
534reopen_error_exit:
Steve Frencha6ce4932009-04-09 01:14:32 +0000535 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000537 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
539
Steve French3a9f4622007-04-04 17:10:24 +0000540 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 if (oplockEnabled)
544 oplock = REQ_OPLOCK;
545 else
Steve French4b18f2a2008-04-29 00:06:05 +0000546 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Steve French7fc8f4e2009-02-23 20:43:11 +0000548 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
549 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
550 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
551 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
552 /* can not refresh inode info since size could be stale */
553 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
554 cifs_sb->mnt_file_mode /* ignored */,
555 oflags, &oplock, &netfid, xid);
556 if (rc == 0) {
557 cFYI(1, ("posix reopen succeeded"));
558 goto reopen_success;
559 }
560 /* fallthrough to retry open the old way on errors, especially
561 in the reconnect path it is important to retry hard */
562 }
563
564 desiredAccess = cifs_convert_flags(file->f_flags);
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000567 by SMBOpen and then calling get_inode_info with returned buf
568 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 and server version of file size can be stale. If we knew for sure
570 that inode was not dirty locally we could do this */
571
Steve French7fc8f4e2009-02-23 20:43:11 +0000572 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700575 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if (rc) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000577 mutex_lock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000578 cFYI(1, ("cifs_open returned 0x%x", rc));
579 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000581reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000583 pCifsFile->invalidHandle = false;
Steve Frencha6ce4932009-04-09 01:14:32 +0000584 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 pCifsInode = CIFS_I(inode);
586 if (pCifsInode) {
587 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000588 rc = filemap_write_and_wait(inode->i_mapping);
589 if (rc != 0)
590 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 /* temporarily disable caching while we
592 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000593 pCifsInode->clientCanCacheAll = false;
594 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000595 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 rc = cifs_get_inode_info_unix(&inode,
597 full_path, inode->i_sb, xid);
598 else
599 rc = cifs_get_inode_info(&inode,
600 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000601 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 } /* else we are writing out data to server already
603 and could deadlock if we tried to flush data, and
604 since we do not know if we have data that would
605 invalidate the current end of file on the server
606 we can not go to the server to get the new inod
607 info */
608 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000609 pCifsInode->clientCanCacheAll = true;
610 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800612 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000614 pCifsInode->clientCanCacheRead = true;
615 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000617 pCifsInode->clientCanCacheRead = false;
618 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
620 cifs_relock_file(pCifsFile);
621 }
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 kfree(full_path);
624 FreeXid(xid);
625 return rc;
626}
627
628int cifs_close(struct inode *inode, struct file *file)
629{
630 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000631 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 struct cifs_sb_info *cifs_sb;
633 struct cifsTconInfo *pTcon;
634 struct cifsFileInfo *pSMBFile =
635 (struct cifsFileInfo *)file->private_data;
636
637 xid = GetXid();
638
639 cifs_sb = CIFS_SB(inode->i_sb);
640 pTcon = cifs_sb->tcon;
641 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000642 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000643 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000644 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (pTcon) {
646 /* no sense reconnecting to close a file that is
647 already closed */
Steve French3b795212008-11-13 19:45:32 +0000648 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000649 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000650 timeout = 2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000651 while ((atomic_read(&pSMBFile->wrtPending) != 0)
Steve French15745322007-09-07 22:23:48 +0000652 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700653 /* Give write a better chance to get to
654 server ahead of the close. We do not
655 want to add a wait_q here as it would
656 increase the memory utilization as
657 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000658 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700659 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000660 cFYI(DBG2,
661 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700662 msleep(timeout);
663 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000664 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000665 if (atomic_read(&pSMBFile->wrtPending))
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000666 cERROR(1, ("close with pending write"));
667 if (!pTcon->need_reconnect &&
668 !pSMBFile->invalidHandle)
669 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000671 } else
672 write_unlock(&GlobalSMBSeslock);
673 } else
674 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000675
676 /* Delete any outstanding lock records.
677 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000678 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000679 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
680 list_del(&li->llist);
681 kfree(li);
682 }
Roland Dreier796e5662007-05-03 04:33:45 +0000683 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000684
Steve Frenchcbe04762005-04-28 22:41:05 -0700685 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 list_del(&pSMBFile->flist);
687 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700688 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000689 timeout = 10;
690 /* We waited above to give the SMBWrite a chance to issue
691 on the wire (so we do not get SMBWrite returning EBADF
692 if writepages is racing with close. Note that writepages
693 does not specify a file handle, so it is possible for a file
694 to be opened twice, and the application close the "wrong"
695 file handle - in these cases we delay long enough to allow
696 the SMBWrite to get on the wire before the SMB Close.
697 We allow total wait here over 45 seconds, more than
698 oplock break time, and more than enough to allow any write
699 to complete on the server, or to time out on the client */
700 while ((atomic_read(&pSMBFile->wrtPending) != 0)
701 && (timeout <= 50000)) {
702 cERROR(1, ("writes pending, delay free of handle"));
703 msleep(timeout);
704 timeout *= 8;
705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 kfree(file->private_data);
707 file->private_data = NULL;
708 } else
709 rc = -EBADF;
710
Steve French4efa53f2007-09-11 05:50:53 +0000711 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (list_empty(&(CIFS_I(inode)->openFileList))) {
713 cFYI(1, ("closing last open instance for inode %p", inode));
714 /* if the file is not open we do not know if we can cache info
715 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000716 CIFS_I(inode)->clientCanCacheRead = false;
717 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
Steve French4efa53f2007-09-11 05:50:53 +0000719 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000720 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 rc = CIFS_I(inode)->write_behind_rc;
722 FreeXid(xid);
723 return rc;
724}
725
726int cifs_closedir(struct inode *inode, struct file *file)
727{
728 int rc = 0;
729 int xid;
730 struct cifsFileInfo *pCFileStruct =
731 (struct cifsFileInfo *)file->private_data;
732 char *ptmp;
733
Steve French26a21b92006-05-31 18:05:34 +0000734 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 xid = GetXid();
737
738 if (pCFileStruct) {
739 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000740 struct cifs_sb_info *cifs_sb =
741 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 pTcon = cifs_sb->tcon;
744
745 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000746 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000747 if (!pCFileStruct->srch_inf.endOfSearch &&
748 !pCFileStruct->invalidHandle) {
749 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000750 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
752 cFYI(1, ("Closing uncompleted readdir with rc %d",
753 rc));
754 /* not much we can do if it fails anyway, ignore rc */
755 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000756 } else
757 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
759 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800760 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000762 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000763 cifs_small_buf_release(ptmp);
764 else
765 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 kfree(file->private_data);
768 file->private_data = NULL;
769 }
770 /* BB can we lock the filestruct while this is going on? */
771 FreeXid(xid);
772 return rc;
773}
774
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000775static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
776 __u64 offset, __u8 lockType)
777{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000778 struct cifsLockInfo *li =
779 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000780 if (li == NULL)
781 return -ENOMEM;
782 li->offset = offset;
783 li->length = len;
784 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000785 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000786 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000787 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000788 return 0;
789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
792{
793 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 __u32 numLock = 0;
795 __u32 numUnlock = 0;
796 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000797 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000799 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000800 __u16 netfid;
801 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000802 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 length = 1 + pfLock->fl_end - pfLock->fl_start;
805 rc = -EACCES;
806 xid = GetXid();
807
808 cFYI(1, ("Lock parm: 0x%x flockflags: "
809 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000810 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
811 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000814 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000816 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000818 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000819 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821 if (pfLock->fl_flags & FL_ACCESS)
822 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000823 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (pfLock->fl_flags & FL_LEASE)
825 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000826 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
828 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
829
830 if (pfLock->fl_type == F_WRLCK) {
831 cFYI(1, ("F_WRLCK "));
832 numLock = 1;
833 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000834 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000836 /* Check if unlock includes more than
837 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000839 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 lockType |= LOCKING_ANDX_SHARED_LOCK;
841 numLock = 1;
842 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000843 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 numLock = 1;
845 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000846 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 lockType |= LOCKING_ANDX_SHARED_LOCK;
848 numLock = 1;
849 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000850 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800852 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000853 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 if (file->private_data == NULL) {
856 FreeXid(xid);
857 return -EBADF;
858 }
Steve French08547b02006-02-28 22:39:25 +0000859 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Steve French13a6e422008-12-02 17:24:33 +0000861 if ((tcon->ses->capabilities & CAP_UNIX) &&
862 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000863 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000864 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000865 /* BB add code here to normalize offset and length to
866 account for negative length which we can not accept over the
867 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000869 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000870 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000871 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000872 posix_lock_type = CIFS_RDLCK;
873 else
874 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000875 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000876 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000877 posix_lock_type, wait_flag);
878 FreeXid(xid);
879 return rc;
880 }
881
882 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000883 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000884 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000886 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 pfLock->fl_start, 1 /* numUnlock */ ,
888 0 /* numLock */ , lockType,
889 0 /* wait flag */ );
890 pfLock->fl_type = F_UNLCK;
891 if (rc != 0)
892 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000893 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 rc = 0;
895
896 } else {
897 /* if rc == ERR_SHARING_VIOLATION ? */
898 rc = 0; /* do not change lock type to unlock
899 since range in use */
900 }
901
902 FreeXid(xid);
903 return rc;
904 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000905
906 if (!numLock && !numUnlock) {
907 /* if no lock or unlock then nothing
908 to do since we do not know what it is */
909 FreeXid(xid);
910 return -EOPNOTSUPP;
911 }
912
913 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000914 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000915 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000916 posix_lock_type = CIFS_RDLCK;
917 else
918 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000919
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000920 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000921 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000922
Steve French13a6e422008-12-02 17:24:33 +0000923 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000924 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000925 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000926 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000927 struct cifsFileInfo *fid =
928 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000929
930 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000931 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000932 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000933 0, numLock, lockType, wait_flag);
934
935 if (rc == 0) {
936 /* For Windows locks we must store them. */
937 rc = store_file_lock(fid, length,
938 pfLock->fl_start, lockType);
939 }
940 } else if (numUnlock) {
941 /* For each stored lock that this unlock overlaps
942 completely, unlock it. */
943 int stored_rc = 0;
944 struct cifsLockInfo *li, *tmp;
945
Steve French6b70c952006-09-21 07:35:29 +0000946 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000947 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000948 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
949 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000950 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000951 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000952 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000953 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000954 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000955 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000956 if (stored_rc)
957 rc = stored_rc;
958
959 list_del(&li->llist);
960 kfree(li);
961 }
962 }
Roland Dreier796e5662007-05-03 04:33:45 +0000963 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000964 }
965 }
966
Steve Frenchd634cc12005-08-26 14:42:59 -0500967 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 posix_lock_file_wait(file, pfLock);
969 FreeXid(xid);
970 return rc;
971}
972
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400973/*
974 * Set the timeout on write requests past EOF. For some servers (Windows)
975 * these calls can be very long.
976 *
977 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
978 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
979 * The 10M cutoff is totally arbitrary. A better scheme for this would be
980 * welcome if someone wants to suggest one.
981 *
982 * We may be able to do a better job with this if there were some way to
983 * declare that a file should be sparse.
984 */
985static int
986cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
987{
988 if (offset <= cifsi->server_eof)
989 return CIFS_STD_OP;
990 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
991 return CIFS_VLONG_OP;
992 else
993 return CIFS_LONG_OP;
994}
995
996/* update the file size (if needed) after a write */
997static void
998cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
999 unsigned int bytes_written)
1000{
1001 loff_t end_of_write = offset + bytes_written;
1002
1003 if (end_of_write > cifsi->server_eof)
1004 cifsi->server_eof = end_of_write;
1005}
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007ssize_t cifs_user_write(struct file *file, const char __user *write_data,
1008 size_t write_size, loff_t *poffset)
1009{
1010 int rc = 0;
1011 unsigned int bytes_written = 0;
1012 unsigned int total_written;
1013 struct cifs_sb_info *cifs_sb;
1014 struct cifsTconInfo *pTcon;
1015 int xid, long_op;
1016 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001017 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001019 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021 pTcon = cifs_sb->tcon;
1022
1023 /* cFYI(1,
1024 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001025 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 if (file->private_data == NULL)
1028 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001029 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001030
Jeff Layton838726c2008-08-28 07:54:59 -04001031 rc = generic_write_checks(file, poffset, &write_size, 0);
1032 if (rc)
1033 return rc;
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001037 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 for (total_written = 0; write_size > total_written;
1039 total_written += bytes_written) {
1040 rc = -EAGAIN;
1041 while (rc == -EAGAIN) {
1042 if (file->private_data == NULL) {
1043 /* file has been closed on us */
1044 FreeXid(xid);
1045 /* if we have gotten here we have written some data
1046 and blocked, and the file has been freed on us while
1047 we blocked so return what we managed to write */
1048 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (open_file->closePend) {
1051 FreeXid(xid);
1052 if (total_written)
1053 return total_written;
1054 else
1055 return -EBADF;
1056 }
1057 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 /* we could deadlock if we called
1059 filemap_fdatawait from here so tell
1060 reopen_file not to flush data to server
1061 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001062 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 if (rc != 0)
1064 break;
1065 }
1066
1067 rc = CIFSSMBWrite(xid, pTcon,
1068 open_file->netfid,
1069 min_t(const int, cifs_sb->wsize,
1070 write_size - total_written),
1071 *poffset, &bytes_written,
1072 NULL, write_data + total_written, long_op);
1073 }
1074 if (rc || (bytes_written == 0)) {
1075 if (total_written)
1076 break;
1077 else {
1078 FreeXid(xid);
1079 return rc;
1080 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001081 } else {
1082 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001084 }
Steve French133672e2007-11-13 22:41:37 +00001085 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 15 seconds is plenty */
1087 }
1088
Steve Frencha4544342005-08-24 13:59:35 -07001089 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
1091 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001092 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1093 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001094/* Do not update local mtime - server will set its actual value on write
1095 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001096 * current_fs_time(inode->i_sb);*/
1097 if (total_written > 0) {
1098 spin_lock(&inode->i_lock);
1099 if (*poffset > file->f_path.dentry->d_inode->i_size)
1100 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001102 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001104 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106 FreeXid(xid);
1107 return total_written;
1108}
1109
1110static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001111 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
1113 int rc = 0;
1114 unsigned int bytes_written = 0;
1115 unsigned int total_written;
1116 struct cifs_sb_info *cifs_sb;
1117 struct cifsTconInfo *pTcon;
1118 int xid, long_op;
1119 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001120 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001122 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 pTcon = cifs_sb->tcon;
1125
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001126 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001127 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 if (file->private_data == NULL)
1130 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001131 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001135 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 for (total_written = 0; write_size > total_written;
1137 total_written += bytes_written) {
1138 rc = -EAGAIN;
1139 while (rc == -EAGAIN) {
1140 if (file->private_data == NULL) {
1141 /* file has been closed on us */
1142 FreeXid(xid);
1143 /* if we have gotten here we have written some data
1144 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001145 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 write */
1147 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 if (open_file->closePend) {
1150 FreeXid(xid);
1151 if (total_written)
1152 return total_written;
1153 else
1154 return -EBADF;
1155 }
1156 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 /* we could deadlock if we called
1158 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001159 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001161 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (rc != 0)
1163 break;
1164 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001165 if (experimEnabled || (pTcon->ses->server &&
1166 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001167 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001168 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001169 struct kvec iov[2];
1170 unsigned int len;
1171
Steve French0ae0efa2005-10-10 10:57:19 -07001172 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001173 write_size - total_written);
1174 /* iov[0] is reserved for smb header */
1175 iov[1].iov_base = (char *)write_data +
1176 total_written;
1177 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001178 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001179 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001180 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001181 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001182 } else
Steve French60808232006-04-22 15:53:05 +00001183 rc = CIFSSMBWrite(xid, pTcon,
1184 open_file->netfid,
1185 min_t(const int, cifs_sb->wsize,
1186 write_size - total_written),
1187 *poffset, &bytes_written,
1188 write_data + total_written,
1189 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191 if (rc || (bytes_written == 0)) {
1192 if (total_written)
1193 break;
1194 else {
1195 FreeXid(xid);
1196 return rc;
1197 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001198 } else {
1199 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001201 }
Steve French133672e2007-11-13 22:41:37 +00001202 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 15 seconds is plenty */
1204 }
1205
Steve Frencha4544342005-08-24 13:59:35 -07001206 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001209 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001210/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001211/* file->f_path.dentry->d_inode->i_ctime =
1212 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1213 if (total_written > 0) {
1214 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1215 if (*poffset > file->f_path.dentry->d_inode->i_size)
1216 i_size_write(file->f_path.dentry->d_inode,
1217 *poffset);
1218 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
Steve French3677db12007-02-26 16:46:11 +00001220 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222 FreeXid(xid);
1223 return total_written;
1224}
1225
Steve French630f3f0c2007-10-25 21:17:17 +00001226#ifdef CONFIG_CIFS_EXPERIMENTAL
1227struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1228{
1229 struct cifsFileInfo *open_file = NULL;
1230
1231 read_lock(&GlobalSMBSeslock);
1232 /* we could simply get the first_list_entry since write-only entries
1233 are always at the end of the list but since the first entry might
1234 have a close pending, we go through the whole list */
1235 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1236 if (open_file->closePend)
1237 continue;
1238 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1239 (open_file->pfile->f_flags & O_RDONLY))) {
1240 if (!open_file->invalidHandle) {
1241 /* found a good file */
1242 /* lock it so it will not be closed on us */
1243 atomic_inc(&open_file->wrtPending);
1244 read_unlock(&GlobalSMBSeslock);
1245 return open_file;
1246 } /* else might as well continue, and look for
1247 another, or simply have the caller reopen it
1248 again rather than trying to fix this handle */
1249 } else /* write only file */
1250 break; /* write only files are last so must be done */
1251 }
1252 read_unlock(&GlobalSMBSeslock);
1253 return NULL;
1254}
1255#endif
1256
Steve Frenchdd99cd82005-10-05 19:32:49 -07001257struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001258{
1259 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001260 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001261 int rc;
Steve French6148a742005-10-05 12:23:19 -07001262
Steve French60808232006-04-22 15:53:05 +00001263 /* Having a null inode here (because mapping->host was set to zero by
1264 the VFS or MM) should not happen but we had reports of on oops (due to
1265 it being zero) during stress testcases so we need to check for it */
1266
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001267 if (cifs_inode == NULL) {
1268 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001269 dump_stack();
1270 return NULL;
1271 }
1272
Steve French6148a742005-10-05 12:23:19 -07001273 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001274refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001275 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001276 if (open_file->closePend ||
1277 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001278 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001279
Steve French6148a742005-10-05 12:23:19 -07001280 if (open_file->pfile &&
1281 ((open_file->pfile->f_flags & O_RDWR) ||
1282 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001283 atomic_inc(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001284
1285 if (!open_file->invalidHandle) {
1286 /* found a good writable file */
1287 read_unlock(&GlobalSMBSeslock);
1288 return open_file;
1289 }
Steve French8840dee2007-11-16 23:05:52 +00001290
Steve French6148a742005-10-05 12:23:19 -07001291 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001292 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001293 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001294 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001295 if (!open_file->closePend)
1296 return open_file;
1297 else { /* start over in case this was deleted */
1298 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001299 read_lock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +00001300 atomic_dec(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001301 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001302 }
1303 }
Steve French9b22b0b2007-10-02 01:11:08 +00001304
1305 /* if it fails, try another handle if possible -
1306 (we can not do this if closePending since
1307 loop could be modified - in which case we
1308 have to start at the beginning of the list
1309 again. Note that it would be bad
1310 to hold up writepages here (rather than
1311 in caller) with continuous retries */
1312 cFYI(1, ("wp failed on reopen file"));
1313 read_lock(&GlobalSMBSeslock);
1314 /* can not use this handle, no write
1315 pending on this one after all */
1316 atomic_dec(&open_file->wrtPending);
Steve French8840dee2007-11-16 23:05:52 +00001317
Steve French9b22b0b2007-10-02 01:11:08 +00001318 if (open_file->closePend) /* list could have changed */
1319 goto refind_writable;
1320 /* else we simply continue to the next entry. Thus
1321 we do not loop on reopen errors. If we
1322 can not reopen the file, for example if we
1323 reconnected to a server with another client
1324 racing to delete or lock the file we would not
1325 make progress if we restarted before the beginning
1326 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001327 }
1328 }
Jeff Layton2846d382008-09-22 21:33:33 -04001329 /* couldn't find useable FH with same pid, try any available */
1330 if (!any_available) {
1331 any_available = true;
1332 goto refind_writable;
1333 }
Steve French6148a742005-10-05 12:23:19 -07001334 read_unlock(&GlobalSMBSeslock);
1335 return NULL;
1336}
1337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1339{
1340 struct address_space *mapping = page->mapping;
1341 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1342 char *write_data;
1343 int rc = -EFAULT;
1344 int bytes_written = 0;
1345 struct cifs_sb_info *cifs_sb;
1346 struct cifsTconInfo *pTcon;
1347 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001348 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 if (!mapping || !mapping->host)
1351 return -EFAULT;
1352
1353 inode = page->mapping->host;
1354 cifs_sb = CIFS_SB(inode->i_sb);
1355 pTcon = cifs_sb->tcon;
1356
1357 offset += (loff_t)from;
1358 write_data = kmap(page);
1359 write_data += from;
1360
1361 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1362 kunmap(page);
1363 return -EIO;
1364 }
1365
1366 /* racing with truncate? */
1367 if (offset > mapping->host->i_size) {
1368 kunmap(page);
1369 return 0; /* don't care */
1370 }
1371
1372 /* check to make sure that we are not extending the file */
1373 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001374 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Steve French6148a742005-10-05 12:23:19 -07001376 open_file = find_writable_file(CIFS_I(mapping->host));
1377 if (open_file) {
1378 bytes_written = cifs_write(open_file->pfile, write_data,
1379 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001380 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001382 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001383 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001384 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001385 else if (bytes_written < 0)
1386 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001387 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 cFYI(1, ("No writeable filehandles for inode"));
1389 rc = -EIO;
1390 }
1391
1392 kunmap(page);
1393 return rc;
1394}
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001397 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
Steve French37c0eb42005-10-05 14:50:29 -07001399 struct backing_dev_info *bdi = mapping->backing_dev_info;
1400 unsigned int bytes_to_write;
1401 unsigned int bytes_written;
1402 struct cifs_sb_info *cifs_sb;
1403 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001404 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001405 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001406 int range_whole = 0;
1407 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001408 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001409 int n_iov = 0;
1410 pgoff_t next;
1411 int nr_pages;
1412 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001413 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001414 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001415 struct page *page;
1416 struct pagevec pvec;
1417 int rc = 0;
1418 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001419 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Steve French37c0eb42005-10-05 14:50:29 -07001421 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001422
Steve French37c0eb42005-10-05 14:50:29 -07001423 /*
1424 * If wsize is smaller that the page cache size, default to writing
1425 * one page at a time via cifs_writepage
1426 */
1427 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1428 return generic_writepages(mapping, wbc);
1429
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001430 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1431 if (cifs_sb->tcon->ses->server->secMode &
1432 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1433 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001434 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001435
Steve French9a0c8232007-02-02 04:21:57 +00001436 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001437 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001438 return generic_writepages(mapping, wbc);
1439
1440
Steve French37c0eb42005-10-05 14:50:29 -07001441 /*
1442 * BB: Is this meaningful for a non-block-device file system?
1443 * If it is, we should test it again after we do I/O
1444 */
1445 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1446 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001447 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001448 return 0;
1449 }
1450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 xid = GetXid();
1452
Steve French37c0eb42005-10-05 14:50:29 -07001453 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001454 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001455 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001456 end = -1;
1457 } else {
1458 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1459 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1460 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1461 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001462 scanned = 1;
1463 }
1464retry:
1465 while (!done && (index <= end) &&
1466 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1467 PAGECACHE_TAG_DIRTY,
1468 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1469 int first;
1470 unsigned int i;
1471
Steve French37c0eb42005-10-05 14:50:29 -07001472 first = -1;
1473 next = 0;
1474 n_iov = 0;
1475 bytes_to_write = 0;
1476
1477 for (i = 0; i < nr_pages; i++) {
1478 page = pvec.pages[i];
1479 /*
1480 * At this point we hold neither mapping->tree_lock nor
1481 * lock on the page itself: the page may be truncated or
1482 * invalidated (changing page->mapping to NULL), or even
1483 * swizzled back from swapper_space to tmpfs file
1484 * mapping
1485 */
1486
1487 if (first < 0)
1488 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001489 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001490 break;
1491
1492 if (unlikely(page->mapping != mapping)) {
1493 unlock_page(page);
1494 break;
1495 }
1496
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001497 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001498 done = 1;
1499 unlock_page(page);
1500 break;
1501 }
1502
1503 if (next && (page->index != next)) {
1504 /* Not next consecutive page */
1505 unlock_page(page);
1506 break;
1507 }
1508
1509 if (wbc->sync_mode != WB_SYNC_NONE)
1510 wait_on_page_writeback(page);
1511
1512 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001513 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001514 unlock_page(page);
1515 break;
1516 }
Steve French84d2f072005-10-12 15:32:05 -07001517
Linus Torvaldscb876f42006-12-23 16:19:07 -08001518 /*
1519 * This actually clears the dirty bit in the radix tree.
1520 * See cifs_writepage() for more commentary.
1521 */
1522 set_page_writeback(page);
1523
Steve French84d2f072005-10-12 15:32:05 -07001524 if (page_offset(page) >= mapping->host->i_size) {
1525 done = 1;
1526 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001527 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001528 break;
1529 }
1530
Steve French37c0eb42005-10-05 14:50:29 -07001531 /*
1532 * BB can we get rid of this? pages are held by pvec
1533 */
1534 page_cache_get(page);
1535
Steve French84d2f072005-10-12 15:32:05 -07001536 len = min(mapping->host->i_size - page_offset(page),
1537 (loff_t)PAGE_CACHE_SIZE);
1538
Steve French37c0eb42005-10-05 14:50:29 -07001539 /* reserve iov[0] for the smb header */
1540 n_iov++;
1541 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001542 iov[n_iov].iov_len = len;
1543 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001544
1545 if (first < 0) {
1546 first = i;
1547 offset = page_offset(page);
1548 }
1549 next = page->index + 1;
1550 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1551 break;
1552 }
1553 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001554 /* Search for a writable handle every time we call
1555 * CIFSSMBWrite2. We can't rely on the last handle
1556 * we used to still be valid
1557 */
1558 open_file = find_writable_file(CIFS_I(mapping->host));
1559 if (!open_file) {
1560 cERROR(1, ("No writable handles for inode"));
1561 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001562 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001563 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001564 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1565 open_file->netfid,
1566 bytes_to_write, offset,
1567 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001568 long_op);
Steve French23e7dd72005-10-20 13:44:56 -07001569 atomic_dec(&open_file->wrtPending);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001570 cifs_update_eof(cifsi, offset, bytes_written);
1571
Steve French23e7dd72005-10-20 13:44:56 -07001572 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001573 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001574 rc, bytes_written));
1575 /* BB what if continued retry is
1576 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001577 if (rc == -ENOSPC)
1578 set_bit(AS_ENOSPC, &mapping->flags);
1579 else
1580 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001581 } else {
1582 cifs_stats_bytes_written(cifs_sb->tcon,
1583 bytes_written);
1584 }
Steve French37c0eb42005-10-05 14:50:29 -07001585 }
1586 for (i = 0; i < n_iov; i++) {
1587 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001588 /* Should we also set page error on
1589 success rc but too little data written? */
1590 /* BB investigate retry logic on temporary
1591 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001592 when page marked as error */
1593 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001594 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001595 kunmap(page);
1596 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001597 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001598 page_cache_release(page);
1599 }
1600 if ((wbc->nr_to_write -= n_iov) <= 0)
1601 done = 1;
1602 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001603 } else
1604 /* Need to re-find the pages we skipped */
1605 index = pvec.pages[0]->index + 1;
1606
Steve French37c0eb42005-10-05 14:50:29 -07001607 pagevec_release(&pvec);
1608 }
1609 if (!scanned && !done) {
1610 /*
1611 * We hit the last page and there is more work to be done: wrap
1612 * back to the start of the file
1613 */
1614 scanned = 1;
1615 index = 0;
1616 goto retry;
1617 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001618 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001619 mapping->writeback_index = index;
1620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001622 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return rc;
1624}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001626static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627{
1628 int rc = -EFAULT;
1629 int xid;
1630
1631 xid = GetXid();
1632/* BB add check for wbc flags */
1633 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001634 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001636
1637 /*
1638 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1639 *
1640 * A writepage() implementation always needs to do either this,
1641 * or re-dirty the page with "redirty_page_for_writepage()" in
1642 * the case of a failure.
1643 *
1644 * Just unlocking the page will cause the radix tree tag-bits
1645 * to fail to update with the state of the page correctly.
1646 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001647 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1649 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1650 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001651 end_page_writeback(page);
1652 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 FreeXid(xid);
1654 return rc;
1655}
1656
Nick Piggind9414772008-09-24 11:32:59 -04001657static int cifs_write_end(struct file *file, struct address_space *mapping,
1658 loff_t pos, unsigned len, unsigned copied,
1659 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
Nick Piggind9414772008-09-24 11:32:59 -04001661 int rc;
1662 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Nick Piggind9414772008-09-24 11:32:59 -04001664 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1665 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001666
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001667 if (PageChecked(page)) {
1668 if (copied == len)
1669 SetPageUptodate(page);
1670 ClearPageChecked(page);
1671 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001672 SetPageUptodate(page);
1673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001675 char *page_data;
1676 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1677 int xid;
1678
1679 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 /* this is probably better than directly calling
1681 partialpage_write since in this function the file handle is
1682 known which we might as well leverage */
1683 /* BB check if anything else missing out of ppw
1684 such as updating last write time */
1685 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001686 rc = cifs_write(file, page_data + offset, copied, &pos);
1687 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001689
1690 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001691 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001692 rc = copied;
1693 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 set_page_dirty(page);
1695 }
1696
Nick Piggind9414772008-09-24 11:32:59 -04001697 if (rc > 0) {
1698 spin_lock(&inode->i_lock);
1699 if (pos > inode->i_size)
1700 i_size_write(inode, pos);
1701 spin_unlock(&inode->i_lock);
1702 }
1703
1704 unlock_page(page);
1705 page_cache_release(page);
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 return rc;
1708}
1709
1710int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1711{
1712 int xid;
1713 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001714 struct cifsTconInfo *tcon;
1715 struct cifsFileInfo *smbfile =
1716 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001717 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719 xid = GetXid();
1720
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001721 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001723
Jeff Laytoncea21802007-11-20 23:19:03 +00001724 rc = filemap_write_and_wait(inode->i_mapping);
1725 if (rc == 0) {
1726 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001728 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001729 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001730 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001731 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001732 }
Steve Frenchb298f222009-02-21 21:17:43 +00001733
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 FreeXid(xid);
1735 return rc;
1736}
1737
NeilBrown3978d7172006-03-26 01:37:17 -08001738/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739{
1740 struct address_space *mapping;
1741 struct inode *inode;
1742 unsigned long index = page->index;
1743 unsigned int rpages = 0;
1744 int rc = 0;
1745
1746 cFYI(1, ("sync page %p",page));
1747 mapping = page->mapping;
1748 if (!mapping)
1749 return 0;
1750 inode = mapping->host;
1751 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001752 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001754/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1756
Steve French26a21b92006-05-31 18:05:34 +00001757/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
NeilBrown3978d7172006-03-26 01:37:17 -08001759#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 if (rc < 0)
1761 return rc;
1762 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001763#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764} */
1765
1766/*
1767 * As file closes, flush all cached write data for this inode checking
1768 * for write behind errors.
1769 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001770int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001772 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 int rc = 0;
1774
1775 /* Rather than do the steps manually:
1776 lock the inode for writing
1777 loop through pages looking for write behind data (dirty pages)
1778 coalesce into contiguous 16K (or smaller) chunks to write to server
1779 send to server (prefer in parallel)
1780 deal with writebehind errors
1781 unlock inode for writing
1782 filemapfdatawrite appears easier for the time being */
1783
1784 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001785 /* reset wb rc if we were able to write out dirty pages */
1786 if (!rc) {
1787 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001789 }
Steve French50c2f752007-07-13 00:33:32 +00001790
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001791 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793 return rc;
1794}
1795
1796ssize_t cifs_user_read(struct file *file, char __user *read_data,
1797 size_t read_size, loff_t *poffset)
1798{
1799 int rc = -EACCES;
1800 unsigned int bytes_read = 0;
1801 unsigned int total_read = 0;
1802 unsigned int current_read_size;
1803 struct cifs_sb_info *cifs_sb;
1804 struct cifsTconInfo *pTcon;
1805 int xid;
1806 struct cifsFileInfo *open_file;
1807 char *smb_read_data;
1808 char __user *current_offset;
1809 struct smb_com_read_rsp *pSMBr;
1810
1811 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001812 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 pTcon = cifs_sb->tcon;
1814
1815 if (file->private_data == NULL) {
1816 FreeXid(xid);
1817 return -EBADF;
1818 }
1819 open_file = (struct cifsFileInfo *)file->private_data;
1820
Steve Frenchad7a2922008-02-07 23:25:02 +00001821 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 for (total_read = 0, current_offset = read_data;
1825 read_size > total_read;
1826 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001827 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 cifs_sb->rsize);
1829 rc = -EAGAIN;
1830 smb_read_data = NULL;
1831 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001832 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001833 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001835 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (rc != 0)
1837 break;
1838 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001839 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001840 open_file->netfid,
1841 current_read_size, *poffset,
1842 &bytes_read, &smb_read_data,
1843 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001846 if (copy_to_user(current_offset,
1847 smb_read_data +
1848 4 /* RFC1001 length field */ +
1849 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001850 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001851 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001852
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001853 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001854 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001855 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001856 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 smb_read_data = NULL;
1858 }
1859 }
1860 if (rc || (bytes_read == 0)) {
1861 if (total_read) {
1862 break;
1863 } else {
1864 FreeXid(xid);
1865 return rc;
1866 }
1867 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001868 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 *poffset += bytes_read;
1870 }
1871 }
1872 FreeXid(xid);
1873 return total_read;
1874}
1875
1876
1877static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1878 loff_t *poffset)
1879{
1880 int rc = -EACCES;
1881 unsigned int bytes_read = 0;
1882 unsigned int total_read;
1883 unsigned int current_read_size;
1884 struct cifs_sb_info *cifs_sb;
1885 struct cifsTconInfo *pTcon;
1886 int xid;
1887 char *current_offset;
1888 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001889 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001892 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 pTcon = cifs_sb->tcon;
1894
1895 if (file->private_data == NULL) {
1896 FreeXid(xid);
1897 return -EBADF;
1898 }
1899 open_file = (struct cifsFileInfo *)file->private_data;
1900
1901 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1902 cFYI(1, ("attempting read on write only file instance"));
1903
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001904 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 read_size > total_read;
1906 total_read += bytes_read, current_offset += bytes_read) {
1907 current_read_size = min_t(const int, read_size - total_read,
1908 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001909 /* For windows me and 9x we do not want to request more
1910 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001911 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001912 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1913 current_read_size = min_t(const int, current_read_size,
1914 pTcon->ses->server->maxBuf - 128);
1915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 rc = -EAGAIN;
1917 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001918 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001920 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 if (rc != 0)
1922 break;
1923 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001924 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001925 open_file->netfid,
1926 current_read_size, *poffset,
1927 &bytes_read, &current_offset,
1928 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 }
1930 if (rc || (bytes_read == 0)) {
1931 if (total_read) {
1932 break;
1933 } else {
1934 FreeXid(xid);
1935 return rc;
1936 }
1937 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001938 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 *poffset += bytes_read;
1940 }
1941 }
1942 FreeXid(xid);
1943 return total_read;
1944}
1945
1946int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1947{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001948 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 int rc, xid;
1950
1951 xid = GetXid();
1952 rc = cifs_revalidate(dentry);
1953 if (rc) {
1954 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1955 FreeXid(xid);
1956 return rc;
1957 }
1958 rc = generic_file_mmap(file, vma);
1959 FreeXid(xid);
1960 return rc;
1961}
1962
1963
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001964static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 struct list_head *pages, int bytes_read, char *data,
1966 struct pagevec *plru_pvec)
1967{
1968 struct page *page;
1969 char *target;
1970
1971 while (bytes_read > 0) {
1972 if (list_empty(pages))
1973 break;
1974
1975 page = list_entry(pages->prev, struct page, lru);
1976 list_del(&page->lru);
1977
1978 if (add_to_page_cache(page, mapping, page->index,
1979 GFP_KERNEL)) {
1980 page_cache_release(page);
1981 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001982 data += PAGE_CACHE_SIZE;
1983 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 continue;
1985 }
1986
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989 if (PAGE_CACHE_SIZE > bytes_read) {
1990 memcpy(target, data, bytes_read);
1991 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001992 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 PAGE_CACHE_SIZE - bytes_read);
1994 bytes_read = 0;
1995 } else {
1996 memcpy(target, data, PAGE_CACHE_SIZE);
1997 bytes_read -= PAGE_CACHE_SIZE;
1998 }
1999 kunmap_atomic(target, KM_USER0);
2000
2001 flush_dcache_page(page);
2002 SetPageUptodate(page);
2003 unlock_page(page);
2004 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002005 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 data += PAGE_CACHE_SIZE;
2007 }
2008 return;
2009}
2010
2011static int cifs_readpages(struct file *file, struct address_space *mapping,
2012 struct list_head *page_list, unsigned num_pages)
2013{
2014 int rc = -EACCES;
2015 int xid;
2016 loff_t offset;
2017 struct page *page;
2018 struct cifs_sb_info *cifs_sb;
2019 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00002020 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002021 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 char *smb_read_data = NULL;
2023 struct smb_com_read_rsp *pSMBr;
2024 struct pagevec lru_pvec;
2025 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002026 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 xid = GetXid();
2029 if (file->private_data == NULL) {
2030 FreeXid(xid);
2031 return -EBADF;
2032 }
2033 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002034 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00002038 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 for (i = 0; i < num_pages; ) {
2040 unsigned contig_pages;
2041 struct page *tmp_page;
2042 unsigned long expected_index;
2043
2044 if (list_empty(page_list))
2045 break;
2046
2047 page = list_entry(page_list->prev, struct page, lru);
2048 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2049
2050 /* count adjacent pages that we will read into */
2051 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if (tmp_page->index == expected_index) {
2056 contig_pages++;
2057 expected_index++;
2058 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 }
2061 if (contig_pages + i > num_pages)
2062 contig_pages = num_pages - i;
2063
2064 /* for reads over a certain size could initiate async
2065 read ahead */
2066
2067 read_size = contig_pages * PAGE_CACHE_SIZE;
2068 /* Read size needs to be in multiples of one page */
2069 read_size = min_t(const unsigned int, read_size,
2070 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002071 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002072 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 rc = -EAGAIN;
2074 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002075 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002077 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 if (rc != 0)
2079 break;
2080 }
2081
Steve Frenchbfa0d752005-08-31 21:50:37 -07002082 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002083 open_file->netfid,
2084 read_size, offset,
2085 &bytes_read, &smb_read_data,
2086 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002087 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002088 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002091 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002093 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 smb_read_data = NULL;
2095 }
2096 }
2097 }
2098 if ((rc < 0) || (smb_read_data == NULL)) {
2099 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 break;
2101 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002102 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2104 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2105 smb_read_data + 4 /* RFC1001 hdr */ +
2106 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2107
2108 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002109 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002110 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 i++; /* account for partial page */
2112
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002113 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002115 /* BB do we need to verify this common case ?
2116 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 we will hit it on next read */
2118
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002119 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 }
2121 } else {
2122 cFYI(1, ("No bytes read (%d) at offset %lld . "
2123 "Cleaning remaining pages from readahead list",
2124 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002125 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 break;
2128 }
2129 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002130 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002131 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002132 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002133 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 smb_read_data = NULL;
2135 }
2136 bytes_read = 0;
2137 }
2138
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002139 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141/* need to free smb_read_data buf before exit */
2142 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002143 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002144 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002146 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
2150 FreeXid(xid);
2151 return rc;
2152}
2153
2154static int cifs_readpage_worker(struct file *file, struct page *page,
2155 loff_t *poffset)
2156{
2157 char *read_data;
2158 int rc;
2159
2160 page_cache_get(page);
2161 read_data = kmap(page);
2162 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 if (rc < 0)
2167 goto io_error;
2168 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002169 cFYI(1, ("Bytes read %d", rc));
2170
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002171 file->f_path.dentry->d_inode->i_atime =
2172 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 if (PAGE_CACHE_SIZE > rc)
2175 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2176
2177 flush_dcache_page(page);
2178 SetPageUptodate(page);
2179 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002180
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002182 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 page_cache_release(page);
2184 return rc;
2185}
2186
2187static int cifs_readpage(struct file *file, struct page *page)
2188{
2189 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2190 int rc = -EACCES;
2191 int xid;
2192
2193 xid = GetXid();
2194
2195 if (file->private_data == NULL) {
2196 FreeXid(xid);
2197 return -EBADF;
2198 }
2199
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002200 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 page, (int)offset, (int)offset));
2202
2203 rc = cifs_readpage_worker(file, page, &offset);
2204
2205 unlock_page(page);
2206
2207 FreeXid(xid);
2208 return rc;
2209}
2210
Steve Frencha403a0a2007-07-26 15:54:16 +00002211static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2212{
2213 struct cifsFileInfo *open_file;
2214
2215 read_lock(&GlobalSMBSeslock);
2216 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2217 if (open_file->closePend)
2218 continue;
2219 if (open_file->pfile &&
2220 ((open_file->pfile->f_flags & O_RDWR) ||
2221 (open_file->pfile->f_flags & O_WRONLY))) {
2222 read_unlock(&GlobalSMBSeslock);
2223 return 1;
2224 }
2225 }
2226 read_unlock(&GlobalSMBSeslock);
2227 return 0;
2228}
2229
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230/* We do not want to update the file size from server for inodes
2231 open for write - to avoid races with writepage extending
2232 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002233 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 but this is tricky to do without racing with writebehind
2235 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002236bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{
Steve Frencha403a0a2007-07-26 15:54:16 +00002238 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002239 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002240
Steve Frencha403a0a2007-07-26 15:54:16 +00002241 if (is_inode_writable(cifsInode)) {
2242 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002243 struct cifs_sb_info *cifs_sb;
2244
Steve Frenchc32a0b62006-01-12 14:41:28 -08002245 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002246 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002247 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002248 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002249 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002250 }
2251
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002252 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002253 return true;
Steve French7ba52632007-02-08 18:14:13 +00002254
Steve French4b18f2a2008-04-29 00:06:05 +00002255 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002256 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002257 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258}
2259
Nick Piggind9414772008-09-24 11:32:59 -04002260static int cifs_write_begin(struct file *file, struct address_space *mapping,
2261 loff_t pos, unsigned len, unsigned flags,
2262 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
Nick Piggind9414772008-09-24 11:32:59 -04002264 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2265 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002266 loff_t page_start = pos & PAGE_MASK;
2267 loff_t i_size;
2268 struct page *page;
2269 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
Nick Piggind9414772008-09-24 11:32:59 -04002271 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2272
Nick Piggin54566b22009-01-04 12:00:53 -08002273 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002274 if (!page) {
2275 rc = -ENOMEM;
2276 goto out;
2277 }
Nick Piggind9414772008-09-24 11:32:59 -04002278
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002279 if (PageUptodate(page))
2280 goto out;
Steve French8a236262007-03-06 00:31:00 +00002281
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002282 /*
2283 * If we write a full page it will be up to date, no need to read from
2284 * the server. If the write is short, we'll end up doing a sync write
2285 * instead.
2286 */
2287 if (len == PAGE_CACHE_SIZE)
2288 goto out;
2289
2290 /*
2291 * optimize away the read when we have an oplock, and we're not
2292 * expecting to use any of the data we'd be reading in. That
2293 * is, when the page lies beyond the EOF, or straddles the EOF
2294 * and the write will cover all of the existing data.
2295 */
2296 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2297 i_size = i_size_read(mapping->host);
2298 if (page_start >= i_size ||
2299 (offset == 0 && (pos + len) >= i_size)) {
2300 zero_user_segments(page, 0, offset,
2301 offset + len,
2302 PAGE_CACHE_SIZE);
2303 /*
2304 * PageChecked means that the parts of the page
2305 * to which we're not writing are considered up
2306 * to date. Once the data is copied to the
2307 * page, it can be set uptodate.
2308 */
2309 SetPageChecked(page);
2310 goto out;
2311 }
2312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Nick Piggind9414772008-09-24 11:32:59 -04002314 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002315 /*
2316 * might as well read a page, it is fast enough. If we get
2317 * an error, we don't need to return it. cifs_write_end will
2318 * do a sync write instead since PG_uptodate isn't set.
2319 */
2320 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002321 } else {
2322 /* we could try using another file handle if there is one -
2323 but how would we lock it to prevent close of that handle
2324 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002325 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002326 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002327out:
2328 *pagep = page;
2329 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330}
2331
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002332const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 .readpage = cifs_readpage,
2334 .readpages = cifs_readpages,
2335 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002336 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002337 .write_begin = cifs_write_begin,
2338 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 .set_page_dirty = __set_page_dirty_nobuffers,
2340 /* .sync_page = cifs_sync_page, */
2341 /* .direct_IO = */
2342};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002343
2344/*
2345 * cifs_readpages requires the server to support a buffer large enough to
2346 * contain the header plus one complete page of data. Otherwise, we need
2347 * to leave cifs_readpages out of the address space operations.
2348 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002349const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002350 .readpage = cifs_readpage,
2351 .writepage = cifs_writepage,
2352 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002353 .write_begin = cifs_write_begin,
2354 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002355 .set_page_dirty = __set_page_dirty_nobuffers,
2356 /* .sync_page = cifs_sync_page, */
2357 /* .direct_IO = */
2358};