blob: 542e0c874d6458d812409418cca57c95486f99dc [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 *
Steve Frenchf19159d2010-04-21 04:12:10 +00006 * Copyright (C) International Business Machines Corp., 2002,2010
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>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include "cifsfs.h"
37#include "cifspdu.h"
38#include "cifsglob.h"
39#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42#include "cifs_fs_sb.h"
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static inline int cifs_convert_flags(unsigned int flags)
45{
46 if ((flags & O_ACCMODE) == O_RDONLY)
47 return GENERIC_READ;
48 else if ((flags & O_ACCMODE) == O_WRONLY)
49 return GENERIC_WRITE;
50 else if ((flags & O_ACCMODE) == O_RDWR) {
51 /* GENERIC_ALL is too much permission to request
52 can cause unnecessary access denied on create */
53 /* return GENERIC_ALL; */
54 return (GENERIC_READ | GENERIC_WRITE);
55 }
56
Jeff Laytone10f7b52008-05-14 10:21:33 -070057 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
58 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
59 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000060}
Jeff Laytone10f7b52008-05-14 10:21:33 -070061
Steve French7fc8f4e2009-02-23 20:43:11 +000062static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
63{
64 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070065
Steve French7fc8f4e2009-02-23 20:43:11 +000066 if ((flags & O_ACCMODE) == O_RDONLY)
67 posix_flags = FMODE_READ;
68 else if ((flags & O_ACCMODE) == O_WRONLY)
69 posix_flags = FMODE_WRITE;
70 else if ((flags & O_ACCMODE) == O_RDWR) {
71 /* GENERIC_ALL is too much permission to request
72 can cause unnecessary access denied on create */
73 /* return GENERIC_ALL; */
74 posix_flags = FMODE_READ | FMODE_WRITE;
75 }
76 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
77 reopening a file. They had their effect on the original open */
78 if (flags & O_APPEND)
79 posix_flags |= (fmode_t)O_APPEND;
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010080 if (flags & O_DSYNC)
81 posix_flags |= (fmode_t)O_DSYNC;
82 if (flags & __O_SYNC)
83 posix_flags |= (fmode_t)__O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000084 if (flags & O_DIRECTORY)
85 posix_flags |= (fmode_t)O_DIRECTORY;
86 if (flags & O_NOFOLLOW)
87 posix_flags |= (fmode_t)O_NOFOLLOW;
88 if (flags & O_DIRECT)
89 posix_flags |= (fmode_t)O_DIRECT;
90
91 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
93
94static inline int cifs_get_disposition(unsigned int flags)
95{
96 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
97 return FILE_CREATE;
98 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
99 return FILE_OVERWRITE_IF;
100 else if ((flags & O_CREAT) == O_CREAT)
101 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000102 else if ((flags & O_TRUNC) == O_TRUNC)
103 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 else
105 return FILE_OPEN;
106}
107
108/* all arguments to this function must be checked for validity in caller */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400109static inline int
110cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530111 struct cifsInodeInfo *pCifsInode, __u32 oplock,
Jeff Layton590a3fe2009-09-12 11:54:28 -0400112 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000113{
Steve French276a74a2009-03-03 18:00:34 +0000114
Steve French276a74a2009-03-03 18:00:34 +0000115 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000116
117 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
118 if (pCifsInode == NULL) {
119 write_unlock(&GlobalSMBSeslock);
120 return -EINVAL;
121 }
122
Steve French276a74a2009-03-03 18:00:34 +0000123 if (pCifsInode->clientCanCacheRead) {
124 /* we have the inode open somewhere else
125 no need to discard cache data */
126 goto psx_client_can_cache;
127 }
128
129 /* BB FIXME need to fix this check to move it earlier into posix_open
130 BB fIX following section BB FIXME */
131
132 /* if not oplocked, invalidate inode pages if mtime or file
133 size changed */
134/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
135 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
136 (file->f_path.dentry->d_inode->i_size ==
137 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000138 cFYI(1, "inode unchanged on server");
Steve French276a74a2009-03-03 18:00:34 +0000139 } else {
140 if (file->f_path.dentry->d_inode->i_mapping) {
141 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
142 if (rc != 0)
143 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
144 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000145 cFYI(1, "invalidating remote inode since open detected it "
146 "changed");
Steve French276a74a2009-03-03 18:00:34 +0000147 invalidate_remote_inode(file->f_path.dentry->d_inode);
148 } */
149
150psx_client_can_cache:
151 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
152 pCifsInode->clientCanCacheAll = true;
153 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000154 cFYI(1, "Exclusive Oplock granted on inode %p",
155 file->f_path.dentry->d_inode);
Steve French276a74a2009-03-03 18:00:34 +0000156 } else if ((oplock & 0xF) == OPLOCK_READ)
157 pCifsInode->clientCanCacheRead = true;
158
159 /* will have to change the unlock if we reenable the
160 filemap_fdatawrite (which does not seem necessary */
161 write_unlock(&GlobalSMBSeslock);
162 return 0;
163}
164
Steve French703a3b82009-05-21 22:21:53 +0000165static struct cifsFileInfo *
166cifs_fill_filedata(struct file *file)
167{
168 struct list_head *tmp;
169 struct cifsFileInfo *pCifsFile = NULL;
170 struct cifsInodeInfo *pCifsInode = NULL;
171
172 /* search inode for this file and fill in file->private_data */
173 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
174 read_lock(&GlobalSMBSeslock);
175 list_for_each(tmp, &pCifsInode->openFileList) {
176 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
177 if ((pCifsFile->pfile == NULL) &&
178 (pCifsFile->pid == current->tgid)) {
179 /* mode set in cifs_create */
180
181 /* needed for writepage */
182 pCifsFile->pfile = file;
183 file->private_data = pCifsFile;
184 break;
185 }
186 }
187 read_unlock(&GlobalSMBSeslock);
188
189 if (file->private_data != NULL) {
190 return pCifsFile;
191 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000192 cERROR(1, "could not find file instance for "
193 "new file %p", file);
Steve French703a3b82009-05-21 22:21:53 +0000194 return NULL;
195}
196
Steve French276a74a2009-03-03 18:00:34 +0000197/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
199 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
200 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
201 char *full_path, int xid)
202{
203 struct timespec temp;
204 int rc;
205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (pCifsInode->clientCanCacheRead) {
207 /* we have the inode open somewhere else
208 no need to discard cache data */
209 goto client_can_cache;
210 }
211
212 /* BB need same check in cifs_create too? */
213 /* if not oplocked, invalidate inode pages if mtime or file
214 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400215 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800216 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
217 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000219 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800221 if (file->f_path.dentry->d_inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000222 /* BB no need to lock inode until after invalidate
223 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000224 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
225 if (rc != 0)
226 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000228 cFYI(1, "invalidating remote inode since open detected it "
229 "changed");
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800230 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 }
232
233client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000234 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800235 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 full_path, inode->i_sb, xid);
237 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800238 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000239 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
241 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000242 pCifsInode->clientCanCacheAll = true;
243 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000244 cFYI(1, "Exclusive Oplock granted on inode %p",
245 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000247 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249 return rc;
250}
251
252int cifs_open(struct inode *inode, struct file *file)
253{
254 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400255 int xid;
256 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000258 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 struct cifsFileInfo *pCifsFile;
260 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 char *full_path = NULL;
262 int desiredAccess;
263 int disposition;
264 __u16 netfid;
265 FILE_ALL_INFO *buf = NULL;
266
267 xid = GetXid();
268
269 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000270 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Steve Frencha6ce4932009-04-09 01:14:32 +0000272 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000273 pCifsFile = cifs_fill_filedata(file);
274 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530275 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000276 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530277 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800280 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530282 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530284 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
286
Joe Perchesb6b38f72010-04-21 03:50:45 +0000287 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
288 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000289
290 if (oplockEnabled)
291 oplock = REQ_OPLOCK;
292 else
293 oplock = 0;
294
Steve French64cc2c62009-03-04 19:54:08 +0000295 if (!tcon->broken_posix_open && tcon->unix_ext &&
296 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000297 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
298 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
299 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
Steve Frenchfa588e02010-04-22 19:21:55 +0000300 oflags |= SMB_O_CREAT;
Steve French276a74a2009-03-03 18:00:34 +0000301 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400302 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000303 cifs_sb->mnt_file_mode /* ignored */,
304 oflags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000305 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000306 cFYI(1, "posix open succeeded");
Steve French276a74a2009-03-03 18:00:34 +0000307 /* no need for special case handling of setting mode
308 on read only files needed here */
309
Jeff Layton2422f672010-06-16 13:40:16 -0400310 pCifsFile = cifs_new_fileinfo(inode, netfid, file,
311 file->f_path.mnt,
312 oflags);
313 if (pCifsFile == NULL) {
314 CIFSSMBClose(xid, tcon, netfid);
315 rc = -ENOMEM;
316 goto out;
317 }
318 file->private_data = pCifsFile;
319
Steve French276a74a2009-03-03 18:00:34 +0000320 cifs_posix_open_inode_helper(inode, file, pCifsInode,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530321 oplock, netfid);
Steve French276a74a2009-03-03 18:00:34 +0000322 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000323 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
324 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000325 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000326 " unexpected error on SMB posix open"
327 ", disabling posix open support."
328 " Check if server update available.",
329 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000330 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000331 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000332 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
333 (rc != -EOPNOTSUPP)) /* path not found or net err */
334 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000335 /* else fallthrough to retry open the old way on network i/o
336 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000337 }
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 desiredAccess = cifs_convert_flags(file->f_flags);
340
341/*********************************************************************
342 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000343 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000345 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 * O_CREAT FILE_OPEN_IF
347 * O_CREAT | O_EXCL FILE_CREATE
348 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
349 * O_TRUNC FILE_OVERWRITE
350 * none of the above FILE_OPEN
351 *
352 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000353 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 * O_CREAT | O_TRUNC is similar but truncates the existing
355 * file rather than creating a new file as FILE_SUPERSEDE does
356 * (which uses the attributes / metadata passed in on open call)
357 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000358 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 *? and the read write flags match reasonably. O_LARGEFILE
360 *? is irrelevant because largefile support is always used
361 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
362 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
363 *********************************************************************/
364
365 disposition = cifs_get_disposition(file->f_flags);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 /* BB pass O_SYNC flag through on file attributes .. BB */
368
369 /* Also refresh inode by passing in file_info buf returned by SMBOpen
370 and calling get_inode_info with returned buf (at least helps
371 non-Unix server case) */
372
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000373 /* BB we can not do this if this is the second open of a file
374 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
376 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
377 if (!buf) {
378 rc = -ENOMEM;
379 goto out;
380 }
Steve French5bafd762006-06-07 00:18:43 +0000381
382 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000383 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000384 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700385 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
386 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000387 else
388 rc = -EIO; /* no NT SMB support fall into legacy open below */
389
Steve Frencha9d02ad2005-08-24 23:06:05 -0700390 if (rc == -EIO) {
391 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000392 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700393 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
394 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
395 & CIFS_MOUNT_MAP_SPECIAL_CHR);
396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 goto out;
400 }
Jeff Layton3321b792009-09-25 09:53:37 -0400401
Jeff Layton086f68b2009-09-21 14:08:18 -0400402 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
403 file->f_flags);
404 file->private_data = pCifsFile;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (file->private_data == NULL) {
406 rc = -ENOMEM;
407 goto out;
408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Jeff Layton3321b792009-09-25 09:53:37 -0400410 rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
411 &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000413 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* time to set mode which we can not set earlier due to
415 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000416 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400417 struct cifs_unix_set_info_args args = {
418 .mode = inode->i_mode,
419 .uid = NO_CHANGE_64,
420 .gid = NO_CHANGE_64,
421 .ctime = NO_CHANGE_64,
422 .atime = NO_CHANGE_64,
423 .mtime = NO_CHANGE_64,
424 .device = 0,
425 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400426 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
427 cifs_sb->local_nls,
428 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700429 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 }
431 }
432
433out:
434 kfree(buf);
435 kfree(full_path);
436 FreeXid(xid);
437 return rc;
438}
439
Adrian Bunk04187262006-06-30 18:23:04 +0200440/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441/* to server was lost */
442static int cifs_relock_file(struct cifsFileInfo *cifsFile)
443{
444 int rc = 0;
445
446/* BB list all locks open on this file and relock */
447
448 return rc;
449}
450
Steve French4b18f2a2008-04-29 00:06:05 +0000451static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400454 int xid;
455 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000457 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct cifsFileInfo *pCifsFile;
459 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000460 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 char *full_path = NULL;
462 int desiredAccess;
463 int disposition = FILE_OPEN;
464 __u16 netfid;
465
Steve Frenchad7a2922008-02-07 23:25:02 +0000466 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000468 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return -EBADF;
470
471 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400472 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000473 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400474 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530475 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530477 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800480 if (file->f_path.dentry == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cERROR(1, "no valid name if dentry freed");
Steve French3a9f4622007-04-04 17:10:24 +0000482 dump_stack();
483 rc = -EBADF;
484 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
Steve French3a9f4622007-04-04 17:10:24 +0000486
487 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 if (inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000489 cERROR(1, "inode not valid");
Steve French3a9f4622007-04-04 17:10:24 +0000490 dump_stack();
491 rc = -EBADF;
492 goto reopen_error_exit;
493 }
Steve French50c2f752007-07-13 00:33:32 +0000494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000496 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498/* can not grab rename sem here because various ops, including
499 those that already have the rename sem can end up causing writepage
500 to get called and if the server was down that means we end up here,
501 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800502 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000504 rc = -ENOMEM;
505reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400506 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000508 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
510
Joe Perchesb6b38f72010-04-21 03:50:45 +0000511 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
512 inode, file->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 if (oplockEnabled)
515 oplock = REQ_OPLOCK;
516 else
Steve French4b18f2a2008-04-29 00:06:05 +0000517 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Steve French7fc8f4e2009-02-23 20:43:11 +0000519 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
520 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
521 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
522 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
523 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400524 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000525 cifs_sb->mnt_file_mode /* ignored */,
526 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000527 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000528 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000529 goto reopen_success;
530 }
531 /* fallthrough to retry open the old way on errors, especially
532 in the reconnect path it is important to retry hard */
533 }
534
535 desiredAccess = cifs_convert_flags(file->f_flags);
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000538 by SMBOpen and then calling get_inode_info with returned buf
539 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 and server version of file size can be stale. If we knew for sure
541 that inode was not dirty locally we could do this */
542
Steve French7fc8f4e2009-02-23 20:43:11 +0000543 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000545 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700546 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400548 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000549 cFYI(1, "cifs_open returned 0x%x", rc);
550 cFYI(1, "oplock: %d", oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000552reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000554 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400555 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 pCifsInode = CIFS_I(inode);
557 if (pCifsInode) {
558 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000559 rc = filemap_write_and_wait(inode->i_mapping);
560 if (rc != 0)
561 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 /* temporarily disable caching while we
563 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000564 pCifsInode->clientCanCacheAll = false;
565 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000566 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 rc = cifs_get_inode_info_unix(&inode,
568 full_path, inode->i_sb, xid);
569 else
570 rc = cifs_get_inode_info(&inode,
571 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000572 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 } /* else we are writing out data to server already
574 and could deadlock if we tried to flush data, and
575 since we do not know if we have data that would
576 invalidate the current end of file on the server
577 we can not go to the server to get the new inod
578 info */
579 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000580 pCifsInode->clientCanCacheAll = true;
581 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000582 cFYI(1, "Exclusive Oplock granted on inode %p",
583 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000585 pCifsInode->clientCanCacheRead = true;
586 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000588 pCifsInode->clientCanCacheRead = false;
589 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591 cifs_relock_file(pCifsFile);
592 }
593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 kfree(full_path);
595 FreeXid(xid);
596 return rc;
597}
598
599int cifs_close(struct inode *inode, struct file *file)
600{
601 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000602 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 struct cifs_sb_info *cifs_sb;
604 struct cifsTconInfo *pTcon;
605 struct cifsFileInfo *pSMBFile =
606 (struct cifsFileInfo *)file->private_data;
607
608 xid = GetXid();
609
610 cifs_sb = CIFS_SB(inode->i_sb);
611 pTcon = cifs_sb->tcon;
612 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000613 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000614 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000615 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (pTcon) {
617 /* no sense reconnecting to close a file that is
618 already closed */
Steve French3b795212008-11-13 19:45:32 +0000619 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000620 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000621 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400622 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000623 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700624 /* Give write a better chance to get to
625 server ahead of the close. We do not
626 want to add a wait_q here as it would
627 increase the memory utilization as
628 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000629 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700630 clear the socket */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000631 cFYI(DBG2, "close delay, write pending");
Steve French23e7dd72005-10-20 13:44:56 -0700632 msleep(timeout);
633 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000634 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000635 if (!pTcon->need_reconnect &&
636 !pSMBFile->invalidHandle)
637 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000639 } else
640 write_unlock(&GlobalSMBSeslock);
641 } else
642 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000643
644 /* Delete any outstanding lock records.
645 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000646 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000647 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
648 list_del(&li->llist);
649 kfree(li);
650 }
Roland Dreier796e5662007-05-03 04:33:45 +0000651 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000652
Steve Frenchcbe04762005-04-28 22:41:05 -0700653 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 list_del(&pSMBFile->flist);
655 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700656 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400657 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 file->private_data = NULL;
659 } else
660 rc = -EBADF;
661
Steve French4efa53f2007-09-11 05:50:53 +0000662 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if (list_empty(&(CIFS_I(inode)->openFileList))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "closing last open instance for inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 /* if the file is not open we do not know if we can cache info
666 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000667 CIFS_I(inode)->clientCanCacheRead = false;
668 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
Steve French4efa53f2007-09-11 05:50:53 +0000670 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 rc = CIFS_I(inode)->write_behind_rc;
673 FreeXid(xid);
674 return rc;
675}
676
677int cifs_closedir(struct inode *inode, struct file *file)
678{
679 int rc = 0;
680 int xid;
681 struct cifsFileInfo *pCFileStruct =
682 (struct cifsFileInfo *)file->private_data;
683 char *ptmp;
684
Joe Perchesb6b38f72010-04-21 03:50:45 +0000685 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 xid = GetXid();
688
689 if (pCFileStruct) {
690 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000691 struct cifs_sb_info *cifs_sb =
692 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 pTcon = cifs_sb->tcon;
695
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Freeing private data in close dir");
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000697 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000698 if (!pCFileStruct->srch_inf.endOfSearch &&
699 !pCFileStruct->invalidHandle) {
700 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000701 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000703 cFYI(1, "Closing uncompleted readdir with rc %d",
704 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 /* not much we can do if it fails anyway, ignore rc */
706 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000707 } else
708 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
710 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000711 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000713 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000714 cifs_small_buf_release(ptmp);
715 else
716 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 kfree(file->private_data);
719 file->private_data = NULL;
720 }
721 /* BB can we lock the filestruct while this is going on? */
722 FreeXid(xid);
723 return rc;
724}
725
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000726static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
727 __u64 offset, __u8 lockType)
728{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000729 struct cifsLockInfo *li =
730 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000731 if (li == NULL)
732 return -ENOMEM;
733 li->offset = offset;
734 li->length = len;
735 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000736 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000737 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000738 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000739 return 0;
740}
741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
743{
744 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 __u32 numLock = 0;
746 __u32 numUnlock = 0;
747 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000748 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000750 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000751 __u16 netfid;
752 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000753 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
755 length = 1 + pfLock->fl_end - pfLock->fl_start;
756 rc = -EACCES;
757 xid = GetXid();
758
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000761 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000762 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000765 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000767 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000769 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000770 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000773 cFYI(1, "Process suspended by mandatory locking - "
774 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000776 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000777 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000779 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000782 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 numLock = 1;
784 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000785 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000787 /* Check if unlock includes more than
788 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000790 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 lockType |= LOCKING_ANDX_SHARED_LOCK;
792 numLock = 1;
793 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000794 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 numLock = 1;
796 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000797 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 lockType |= LOCKING_ANDX_SHARED_LOCK;
799 numLock = 1;
800 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000801 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800803 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000804 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530807 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530809 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
Steve French08547b02006-02-28 22:39:25 +0000811 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
Steve French13a6e422008-12-02 17:24:33 +0000813 if ((tcon->ses->capabilities & CAP_UNIX) &&
814 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000815 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000816 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000817 /* BB add code here to normalize offset and length to
818 account for negative length which we can not accept over the
819 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000821 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000822 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000823 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000824 posix_lock_type = CIFS_RDLCK;
825 else
826 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000827 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000828 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000829 posix_lock_type, wait_flag);
830 FreeXid(xid);
831 return rc;
832 }
833
834 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000835 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000836 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000838 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 pfLock->fl_start, 1 /* numUnlock */ ,
840 0 /* numLock */ , lockType,
841 0 /* wait flag */ );
842 pfLock->fl_type = F_UNLCK;
843 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000844 cERROR(1, "Error unlocking previously locked "
845 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 rc = 0;
847
848 } else {
849 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400850 rc = 0;
851
852 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
853 pfLock->fl_type = F_WRLCK;
854 } else {
855 rc = CIFSSMBLock(xid, tcon, netfid, length,
856 pfLock->fl_start, 0, 1,
857 lockType | LOCKING_ANDX_SHARED_LOCK,
858 0 /* wait flag */);
859 if (rc == 0) {
860 rc = CIFSSMBLock(xid, tcon, netfid,
861 length, pfLock->fl_start, 1, 0,
862 lockType |
863 LOCKING_ANDX_SHARED_LOCK,
864 0 /* wait flag */);
865 pfLock->fl_type = F_RDLCK;
866 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000867 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400868 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000869 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400870 rc = 0;
871 } else {
872 pfLock->fl_type = F_WRLCK;
873 rc = 0;
874 }
875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 }
877
878 FreeXid(xid);
879 return rc;
880 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000881
882 if (!numLock && !numUnlock) {
883 /* if no lock or unlock then nothing
884 to do since we do not know what it is */
885 FreeXid(xid);
886 return -EOPNOTSUPP;
887 }
888
889 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000890 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000891 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000892 posix_lock_type = CIFS_RDLCK;
893 else
894 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000895
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000896 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000897 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000898
Steve French13a6e422008-12-02 17:24:33 +0000899 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000900 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000901 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000902 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000903 struct cifsFileInfo *fid =
904 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000905
906 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000907 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000908 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000909 0, numLock, lockType, wait_flag);
910
911 if (rc == 0) {
912 /* For Windows locks we must store them. */
913 rc = store_file_lock(fid, length,
914 pfLock->fl_start, lockType);
915 }
916 } else if (numUnlock) {
917 /* For each stored lock that this unlock overlaps
918 completely, unlock it. */
919 int stored_rc = 0;
920 struct cifsLockInfo *li, *tmp;
921
Steve French6b70c952006-09-21 07:35:29 +0000922 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000923 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
925 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000926 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000927 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000928 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000929 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000930 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000931 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 if (stored_rc)
933 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000934 else {
935 list_del(&li->llist);
936 kfree(li);
937 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000938 }
939 }
Roland Dreier796e5662007-05-03 04:33:45 +0000940 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000941 }
942 }
943
Steve Frenchd634cc12005-08-26 14:42:59 -0500944 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 posix_lock_file_wait(file, pfLock);
946 FreeXid(xid);
947 return rc;
948}
949
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400950/*
951 * Set the timeout on write requests past EOF. For some servers (Windows)
952 * these calls can be very long.
953 *
954 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
955 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
956 * The 10M cutoff is totally arbitrary. A better scheme for this would be
957 * welcome if someone wants to suggest one.
958 *
959 * We may be able to do a better job with this if there were some way to
960 * declare that a file should be sparse.
961 */
962static int
963cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
964{
965 if (offset <= cifsi->server_eof)
966 return CIFS_STD_OP;
967 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
968 return CIFS_VLONG_OP;
969 else
970 return CIFS_LONG_OP;
971}
972
973/* update the file size (if needed) after a write */
974static void
975cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
976 unsigned int bytes_written)
977{
978 loff_t end_of_write = offset + bytes_written;
979
980 if (end_of_write > cifsi->server_eof)
981 cifsi->server_eof = end_of_write;
982}
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984ssize_t cifs_user_write(struct file *file, const char __user *write_data,
985 size_t write_size, loff_t *poffset)
986{
987 int rc = 0;
988 unsigned int bytes_written = 0;
989 unsigned int total_written;
990 struct cifs_sb_info *cifs_sb;
991 struct cifsTconInfo *pTcon;
992 int xid, long_op;
993 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400994 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800996 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 pTcon = cifs_sb->tcon;
999
Joe Perchesb6b38f72010-04-21 03:50:45 +00001000 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
1001 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 if (file->private_data == NULL)
1004 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001005 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001006
Jeff Layton838726c2008-08-28 07:54:59 -04001007 rc = generic_write_checks(file, poffset, &write_size, 0);
1008 if (rc)
1009 return rc;
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001013 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 for (total_written = 0; write_size > total_written;
1015 total_written += bytes_written) {
1016 rc = -EAGAIN;
1017 while (rc == -EAGAIN) {
1018 if (file->private_data == NULL) {
1019 /* file has been closed on us */
1020 FreeXid(xid);
1021 /* if we have gotten here we have written some data
1022 and blocked, and the file has been freed on us while
1023 we blocked so return what we managed to write */
1024 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (open_file->closePend) {
1027 FreeXid(xid);
1028 if (total_written)
1029 return total_written;
1030 else
1031 return -EBADF;
1032 }
1033 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 /* we could deadlock if we called
1035 filemap_fdatawait from here so tell
1036 reopen_file not to flush data to server
1037 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001038 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 if (rc != 0)
1040 break;
1041 }
1042
1043 rc = CIFSSMBWrite(xid, pTcon,
1044 open_file->netfid,
1045 min_t(const int, cifs_sb->wsize,
1046 write_size - total_written),
1047 *poffset, &bytes_written,
1048 NULL, write_data + total_written, long_op);
1049 }
1050 if (rc || (bytes_written == 0)) {
1051 if (total_written)
1052 break;
1053 else {
1054 FreeXid(xid);
1055 return rc;
1056 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001057 } else {
1058 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001060 }
Steve French133672e2007-11-13 22:41:37 +00001061 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 15 seconds is plenty */
1063 }
1064
Steve Frencha4544342005-08-24 13:59:35 -07001065 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001068 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1069 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001070/* Do not update local mtime - server will set its actual value on write
1071 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001072 * current_fs_time(inode->i_sb);*/
1073 if (total_written > 0) {
1074 spin_lock(&inode->i_lock);
1075 if (*poffset > file->f_path.dentry->d_inode->i_size)
1076 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001078 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001080 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 }
1082 FreeXid(xid);
1083 return total_written;
1084}
1085
1086static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001087 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
1089 int rc = 0;
1090 unsigned int bytes_written = 0;
1091 unsigned int total_written;
1092 struct cifs_sb_info *cifs_sb;
1093 struct cifsTconInfo *pTcon;
1094 int xid, long_op;
1095 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001096 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001098 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 pTcon = cifs_sb->tcon;
1101
Joe Perchesb6b38f72010-04-21 03:50:45 +00001102 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
1103 *poffset, file->f_path.dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 if (file->private_data == NULL)
1106 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001107 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001111 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 for (total_written = 0; write_size > total_written;
1113 total_written += bytes_written) {
1114 rc = -EAGAIN;
1115 while (rc == -EAGAIN) {
1116 if (file->private_data == NULL) {
1117 /* file has been closed on us */
1118 FreeXid(xid);
1119 /* if we have gotten here we have written some data
1120 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001121 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 write */
1123 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 if (open_file->closePend) {
1126 FreeXid(xid);
1127 if (total_written)
1128 return total_written;
1129 else
1130 return -EBADF;
1131 }
1132 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 /* we could deadlock if we called
1134 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001135 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001137 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if (rc != 0)
1139 break;
1140 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001141 if (experimEnabled || (pTcon->ses->server &&
1142 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001143 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001144 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001145 struct kvec iov[2];
1146 unsigned int len;
1147
Steve French0ae0efa2005-10-10 10:57:19 -07001148 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001149 write_size - total_written);
1150 /* iov[0] is reserved for smb header */
1151 iov[1].iov_base = (char *)write_data +
1152 total_written;
1153 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001154 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001155 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001156 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001157 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001158 } else
Steve French60808232006-04-22 15:53:05 +00001159 rc = CIFSSMBWrite(xid, pTcon,
1160 open_file->netfid,
1161 min_t(const int, cifs_sb->wsize,
1162 write_size - total_written),
1163 *poffset, &bytes_written,
1164 write_data + total_written,
1165 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167 if (rc || (bytes_written == 0)) {
1168 if (total_written)
1169 break;
1170 else {
1171 FreeXid(xid);
1172 return rc;
1173 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001174 } else {
1175 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001177 }
Steve French133672e2007-11-13 22:41:37 +00001178 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 15 seconds is plenty */
1180 }
1181
Steve Frencha4544342005-08-24 13:59:35 -07001182 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001185 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001186/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001187/* file->f_path.dentry->d_inode->i_ctime =
1188 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1189 if (total_written > 0) {
1190 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1191 if (*poffset > file->f_path.dentry->d_inode->i_size)
1192 i_size_write(file->f_path.dentry->d_inode,
1193 *poffset);
1194 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 }
Steve French3677db12007-02-26 16:46:11 +00001196 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
1198 FreeXid(xid);
1199 return total_written;
1200}
1201
Steve French630f3f0c2007-10-25 21:17:17 +00001202#ifdef CONFIG_CIFS_EXPERIMENTAL
1203struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1204{
1205 struct cifsFileInfo *open_file = NULL;
1206
1207 read_lock(&GlobalSMBSeslock);
1208 /* we could simply get the first_list_entry since write-only entries
1209 are always at the end of the list but since the first entry might
1210 have a close pending, we go through the whole list */
1211 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1212 if (open_file->closePend)
1213 continue;
1214 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1215 (open_file->pfile->f_flags & O_RDONLY))) {
1216 if (!open_file->invalidHandle) {
1217 /* found a good file */
1218 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001219 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001220 read_unlock(&GlobalSMBSeslock);
1221 return open_file;
1222 } /* else might as well continue, and look for
1223 another, or simply have the caller reopen it
1224 again rather than trying to fix this handle */
1225 } else /* write only file */
1226 break; /* write only files are last so must be done */
1227 }
1228 read_unlock(&GlobalSMBSeslock);
1229 return NULL;
1230}
1231#endif
1232
Steve Frenchdd99cd82005-10-05 19:32:49 -07001233struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001234{
1235 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001236 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001237 int rc;
Steve French6148a742005-10-05 12:23:19 -07001238
Steve French60808232006-04-22 15:53:05 +00001239 /* Having a null inode here (because mapping->host was set to zero by
1240 the VFS or MM) should not happen but we had reports of on oops (due to
1241 it being zero) during stress testcases so we need to check for it */
1242
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001243 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001244 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001245 dump_stack();
1246 return NULL;
1247 }
1248
Steve French6148a742005-10-05 12:23:19 -07001249 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001250refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001251 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001252 if (open_file->closePend ||
1253 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001254 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001255
Steve French6148a742005-10-05 12:23:19 -07001256 if (open_file->pfile &&
1257 ((open_file->pfile->f_flags & O_RDWR) ||
1258 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001259 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001260
1261 if (!open_file->invalidHandle) {
1262 /* found a good writable file */
1263 read_unlock(&GlobalSMBSeslock);
1264 return open_file;
1265 }
Steve French8840dee2007-11-16 23:05:52 +00001266
Steve French6148a742005-10-05 12:23:19 -07001267 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001268 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001269 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001270 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001271 if (!open_file->closePend)
1272 return open_file;
1273 else { /* start over in case this was deleted */
1274 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001275 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001276 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001277 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001278 }
1279 }
Steve French9b22b0b2007-10-02 01:11:08 +00001280
1281 /* if it fails, try another handle if possible -
1282 (we can not do this if closePending since
1283 loop could be modified - in which case we
1284 have to start at the beginning of the list
1285 again. Note that it would be bad
1286 to hold up writepages here (rather than
1287 in caller) with continuous retries */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001288 cFYI(1, "wp failed on reopen file");
Steve French9b22b0b2007-10-02 01:11:08 +00001289 read_lock(&GlobalSMBSeslock);
1290 /* can not use this handle, no write
1291 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001292 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001293
Steve French9b22b0b2007-10-02 01:11:08 +00001294 if (open_file->closePend) /* list could have changed */
1295 goto refind_writable;
1296 /* else we simply continue to the next entry. Thus
1297 we do not loop on reopen errors. If we
1298 can not reopen the file, for example if we
1299 reconnected to a server with another client
1300 racing to delete or lock the file we would not
1301 make progress if we restarted before the beginning
1302 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001303 }
1304 }
Jeff Layton2846d382008-09-22 21:33:33 -04001305 /* couldn't find useable FH with same pid, try any available */
1306 if (!any_available) {
1307 any_available = true;
1308 goto refind_writable;
1309 }
Steve French6148a742005-10-05 12:23:19 -07001310 read_unlock(&GlobalSMBSeslock);
1311 return NULL;
1312}
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1315{
1316 struct address_space *mapping = page->mapping;
1317 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1318 char *write_data;
1319 int rc = -EFAULT;
1320 int bytes_written = 0;
1321 struct cifs_sb_info *cifs_sb;
1322 struct cifsTconInfo *pTcon;
1323 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001324 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 if (!mapping || !mapping->host)
1327 return -EFAULT;
1328
1329 inode = page->mapping->host;
1330 cifs_sb = CIFS_SB(inode->i_sb);
1331 pTcon = cifs_sb->tcon;
1332
1333 offset += (loff_t)from;
1334 write_data = kmap(page);
1335 write_data += from;
1336
1337 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1338 kunmap(page);
1339 return -EIO;
1340 }
1341
1342 /* racing with truncate? */
1343 if (offset > mapping->host->i_size) {
1344 kunmap(page);
1345 return 0; /* don't care */
1346 }
1347
1348 /* check to make sure that we are not extending the file */
1349 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001350 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Steve French6148a742005-10-05 12:23:19 -07001352 open_file = find_writable_file(CIFS_I(mapping->host));
1353 if (open_file) {
1354 bytes_written = cifs_write(open_file->pfile, write_data,
1355 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001356 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001358 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001359 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001360 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001361 else if (bytes_written < 0)
1362 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001363 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001364 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 rc = -EIO;
1366 }
1367
1368 kunmap(page);
1369 return rc;
1370}
1371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001373 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Steve French37c0eb42005-10-05 14:50:29 -07001375 struct backing_dev_info *bdi = mapping->backing_dev_info;
1376 unsigned int bytes_to_write;
1377 unsigned int bytes_written;
1378 struct cifs_sb_info *cifs_sb;
1379 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001380 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001381 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001382 int range_whole = 0;
1383 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001384 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001385 int n_iov = 0;
1386 pgoff_t next;
1387 int nr_pages;
1388 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001389 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001390 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001391 struct page *page;
1392 struct pagevec pvec;
1393 int rc = 0;
1394 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001395 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Steve French37c0eb42005-10-05 14:50:29 -07001397 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001398
Steve French37c0eb42005-10-05 14:50:29 -07001399 /*
1400 * If wsize is smaller that the page cache size, default to writing
1401 * one page at a time via cifs_writepage
1402 */
1403 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1404 return generic_writepages(mapping, wbc);
1405
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001406 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1407 if (cifs_sb->tcon->ses->server->secMode &
1408 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1409 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001410 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001411
Steve French9a0c8232007-02-02 04:21:57 +00001412 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001413 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001414 return generic_writepages(mapping, wbc);
1415
1416
Steve French37c0eb42005-10-05 14:50:29 -07001417 /*
1418 * BB: Is this meaningful for a non-block-device file system?
1419 * If it is, we should test it again after we do I/O
1420 */
1421 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1422 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001423 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001424 return 0;
1425 }
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 xid = GetXid();
1428
Steve French37c0eb42005-10-05 14:50:29 -07001429 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001430 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001431 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001432 end = -1;
1433 } else {
1434 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1435 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1436 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1437 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001438 scanned = 1;
1439 }
1440retry:
1441 while (!done && (index <= end) &&
1442 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1443 PAGECACHE_TAG_DIRTY,
1444 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1445 int first;
1446 unsigned int i;
1447
Steve French37c0eb42005-10-05 14:50:29 -07001448 first = -1;
1449 next = 0;
1450 n_iov = 0;
1451 bytes_to_write = 0;
1452
1453 for (i = 0; i < nr_pages; i++) {
1454 page = pvec.pages[i];
1455 /*
1456 * At this point we hold neither mapping->tree_lock nor
1457 * lock on the page itself: the page may be truncated or
1458 * invalidated (changing page->mapping to NULL), or even
1459 * swizzled back from swapper_space to tmpfs file
1460 * mapping
1461 */
1462
1463 if (first < 0)
1464 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001465 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001466 break;
1467
1468 if (unlikely(page->mapping != mapping)) {
1469 unlock_page(page);
1470 break;
1471 }
1472
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001473 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001474 done = 1;
1475 unlock_page(page);
1476 break;
1477 }
1478
1479 if (next && (page->index != next)) {
1480 /* Not next consecutive page */
1481 unlock_page(page);
1482 break;
1483 }
1484
1485 if (wbc->sync_mode != WB_SYNC_NONE)
1486 wait_on_page_writeback(page);
1487
1488 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001489 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001490 unlock_page(page);
1491 break;
1492 }
Steve French84d2f072005-10-12 15:32:05 -07001493
Linus Torvaldscb876f42006-12-23 16:19:07 -08001494 /*
1495 * This actually clears the dirty bit in the radix tree.
1496 * See cifs_writepage() for more commentary.
1497 */
1498 set_page_writeback(page);
1499
Steve French84d2f072005-10-12 15:32:05 -07001500 if (page_offset(page) >= mapping->host->i_size) {
1501 done = 1;
1502 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001503 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001504 break;
1505 }
1506
Steve French37c0eb42005-10-05 14:50:29 -07001507 /*
1508 * BB can we get rid of this? pages are held by pvec
1509 */
1510 page_cache_get(page);
1511
Steve French84d2f072005-10-12 15:32:05 -07001512 len = min(mapping->host->i_size - page_offset(page),
1513 (loff_t)PAGE_CACHE_SIZE);
1514
Steve French37c0eb42005-10-05 14:50:29 -07001515 /* reserve iov[0] for the smb header */
1516 n_iov++;
1517 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001518 iov[n_iov].iov_len = len;
1519 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001520
1521 if (first < 0) {
1522 first = i;
1523 offset = page_offset(page);
1524 }
1525 next = page->index + 1;
1526 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1527 break;
1528 }
1529 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001530 /* Search for a writable handle every time we call
1531 * CIFSSMBWrite2. We can't rely on the last handle
1532 * we used to still be valid
1533 */
1534 open_file = find_writable_file(CIFS_I(mapping->host));
1535 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001536 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001537 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001538 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001539 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001540 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1541 open_file->netfid,
1542 bytes_to_write, offset,
1543 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001544 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001545 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001546 cifs_update_eof(cifsi, offset, bytes_written);
1547
Steve French23e7dd72005-10-20 13:44:56 -07001548 if (rc || bytes_written < bytes_to_write) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001549 cERROR(1, "Write2 ret %d, wrote %d",
1550 rc, bytes_written);
Steve French23e7dd72005-10-20 13:44:56 -07001551 /* BB what if continued retry is
1552 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001553 if (rc == -ENOSPC)
1554 set_bit(AS_ENOSPC, &mapping->flags);
1555 else
1556 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001557 } else {
1558 cifs_stats_bytes_written(cifs_sb->tcon,
1559 bytes_written);
1560 }
Steve French37c0eb42005-10-05 14:50:29 -07001561 }
1562 for (i = 0; i < n_iov; i++) {
1563 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001564 /* Should we also set page error on
1565 success rc but too little data written? */
1566 /* BB investigate retry logic on temporary
1567 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001568 when page marked as error */
1569 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001570 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001571 kunmap(page);
1572 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001573 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001574 page_cache_release(page);
1575 }
1576 if ((wbc->nr_to_write -= n_iov) <= 0)
1577 done = 1;
1578 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001579 } else
1580 /* Need to re-find the pages we skipped */
1581 index = pvec.pages[0]->index + 1;
1582
Steve French37c0eb42005-10-05 14:50:29 -07001583 pagevec_release(&pvec);
1584 }
1585 if (!scanned && !done) {
1586 /*
1587 * We hit the last page and there is more work to be done: wrap
1588 * back to the start of the file
1589 */
1590 scanned = 1;
1591 index = 0;
1592 goto retry;
1593 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001594 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001595 mapping->writeback_index = index;
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001598 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 return rc;
1600}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001602static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603{
1604 int rc = -EFAULT;
1605 int xid;
1606
1607 xid = GetXid();
1608/* BB add check for wbc flags */
1609 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001610 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001611 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001612
1613 /*
1614 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1615 *
1616 * A writepage() implementation always needs to do either this,
1617 * or re-dirty the page with "redirty_page_for_writepage()" in
1618 * the case of a failure.
1619 *
1620 * Just unlocking the page will cause the radix tree tag-bits
1621 * to fail to update with the state of the page correctly.
1622 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001623 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1625 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1626 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001627 end_page_writeback(page);
1628 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 FreeXid(xid);
1630 return rc;
1631}
1632
Nick Piggind9414772008-09-24 11:32:59 -04001633static int cifs_write_end(struct file *file, struct address_space *mapping,
1634 loff_t pos, unsigned len, unsigned copied,
1635 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
Nick Piggind9414772008-09-24 11:32:59 -04001637 int rc;
1638 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
Joe Perchesb6b38f72010-04-21 03:50:45 +00001640 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1641 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001642
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001643 if (PageChecked(page)) {
1644 if (copied == len)
1645 SetPageUptodate(page);
1646 ClearPageChecked(page);
1647 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001648 SetPageUptodate(page);
1649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001651 char *page_data;
1652 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1653 int xid;
1654
1655 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 /* this is probably better than directly calling
1657 partialpage_write since in this function the file handle is
1658 known which we might as well leverage */
1659 /* BB check if anything else missing out of ppw
1660 such as updating last write time */
1661 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001662 rc = cifs_write(file, page_data + offset, copied, &pos);
1663 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001665
1666 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001667 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001668 rc = copied;
1669 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 set_page_dirty(page);
1671 }
1672
Nick Piggind9414772008-09-24 11:32:59 -04001673 if (rc > 0) {
1674 spin_lock(&inode->i_lock);
1675 if (pos > inode->i_size)
1676 i_size_write(inode, pos);
1677 spin_unlock(&inode->i_lock);
1678 }
1679
1680 unlock_page(page);
1681 page_cache_release(page);
1682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 return rc;
1684}
1685
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001686int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
1688 int xid;
1689 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001690 struct cifsTconInfo *tcon;
1691 struct cifsFileInfo *smbfile =
1692 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001693 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
1695 xid = GetXid();
1696
Joe Perchesb6b38f72010-04-21 03:50:45 +00001697 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001698 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001699
Jeff Laytoncea21802007-11-20 23:19:03 +00001700 rc = filemap_write_and_wait(inode->i_mapping);
1701 if (rc == 0) {
1702 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001704 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001705 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001706 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001707 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001708 }
Steve Frenchb298f222009-02-21 21:17:43 +00001709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 FreeXid(xid);
1711 return rc;
1712}
1713
NeilBrown3978d7172006-03-26 01:37:17 -08001714/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 struct address_space *mapping;
1717 struct inode *inode;
1718 unsigned long index = page->index;
1719 unsigned int rpages = 0;
1720 int rc = 0;
1721
Steve Frenchf19159d2010-04-21 04:12:10 +00001722 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 mapping = page->mapping;
1724 if (!mapping)
1725 return 0;
1726 inode = mapping->host;
1727 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001728 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001730/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1732
Joe Perchesb6b38f72010-04-21 03:50:45 +00001733/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
NeilBrown3978d7172006-03-26 01:37:17 -08001735#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (rc < 0)
1737 return rc;
1738 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001739#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740} */
1741
1742/*
1743 * As file closes, flush all cached write data for this inode checking
1744 * for write behind errors.
1745 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001746int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001748 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 int rc = 0;
1750
1751 /* Rather than do the steps manually:
1752 lock the inode for writing
1753 loop through pages looking for write behind data (dirty pages)
1754 coalesce into contiguous 16K (or smaller) chunks to write to server
1755 send to server (prefer in parallel)
1756 deal with writebehind errors
1757 unlock inode for writing
1758 filemapfdatawrite appears easier for the time being */
1759
1760 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001761 /* reset wb rc if we were able to write out dirty pages */
1762 if (!rc) {
1763 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001765 }
Steve French50c2f752007-07-13 00:33:32 +00001766
Joe Perchesb6b38f72010-04-21 03:50:45 +00001767 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 return rc;
1770}
1771
1772ssize_t cifs_user_read(struct file *file, char __user *read_data,
1773 size_t read_size, loff_t *poffset)
1774{
1775 int rc = -EACCES;
1776 unsigned int bytes_read = 0;
1777 unsigned int total_read = 0;
1778 unsigned int current_read_size;
1779 struct cifs_sb_info *cifs_sb;
1780 struct cifsTconInfo *pTcon;
1781 int xid;
1782 struct cifsFileInfo *open_file;
1783 char *smb_read_data;
1784 char __user *current_offset;
1785 struct smb_com_read_rsp *pSMBr;
1786
1787 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001788 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 pTcon = cifs_sb->tcon;
1790
1791 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301792 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301794 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 }
1796 open_file = (struct cifsFileInfo *)file->private_data;
1797
Steve Frenchad7a2922008-02-07 23:25:02 +00001798 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001799 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 for (total_read = 0, current_offset = read_data;
1802 read_size > total_read;
1803 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 cifs_sb->rsize);
1806 rc = -EAGAIN;
1807 smb_read_data = NULL;
1808 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001809 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001812 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if (rc != 0)
1814 break;
1815 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001816 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001817 open_file->netfid,
1818 current_read_size, *poffset,
1819 &bytes_read, &smb_read_data,
1820 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001823 if (copy_to_user(current_offset,
1824 smb_read_data +
1825 4 /* RFC1001 length field */ +
1826 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001827 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001828 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001829
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001830 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001831 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001832 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001833 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 smb_read_data = NULL;
1835 }
1836 }
1837 if (rc || (bytes_read == 0)) {
1838 if (total_read) {
1839 break;
1840 } else {
1841 FreeXid(xid);
1842 return rc;
1843 }
1844 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001845 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 *poffset += bytes_read;
1847 }
1848 }
1849 FreeXid(xid);
1850 return total_read;
1851}
1852
1853
1854static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1855 loff_t *poffset)
1856{
1857 int rc = -EACCES;
1858 unsigned int bytes_read = 0;
1859 unsigned int total_read;
1860 unsigned int current_read_size;
1861 struct cifs_sb_info *cifs_sb;
1862 struct cifsTconInfo *pTcon;
1863 int xid;
1864 char *current_offset;
1865 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001866 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001869 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 pTcon = cifs_sb->tcon;
1871
1872 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301873 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301875 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877 open_file = (struct cifsFileInfo *)file->private_data;
1878
1879 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001880 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001882 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 read_size > total_read;
1884 total_read += bytes_read, current_offset += bytes_read) {
1885 current_read_size = min_t(const int, read_size - total_read,
1886 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001887 /* For windows me and 9x we do not want to request more
1888 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001889 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001890 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1891 current_read_size = min_t(const int, current_read_size,
1892 pTcon->ses->server->maxBuf - 128);
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 rc = -EAGAIN;
1895 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001896 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001898 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 if (rc != 0)
1900 break;
1901 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001902 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001903 open_file->netfid,
1904 current_read_size, *poffset,
1905 &bytes_read, &current_offset,
1906 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 }
1908 if (rc || (bytes_read == 0)) {
1909 if (total_read) {
1910 break;
1911 } else {
1912 FreeXid(xid);
1913 return rc;
1914 }
1915 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001916 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 *poffset += bytes_read;
1918 }
1919 }
1920 FreeXid(xid);
1921 return total_read;
1922}
1923
1924int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1925{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 int rc, xid;
1927
1928 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001929 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001931 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 FreeXid(xid);
1933 return rc;
1934 }
1935 rc = generic_file_mmap(file, vma);
1936 FreeXid(xid);
1937 return rc;
1938}
1939
1940
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001941static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001942 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 struct page *page;
1945 char *target;
1946
1947 while (bytes_read > 0) {
1948 if (list_empty(pages))
1949 break;
1950
1951 page = list_entry(pages->prev, struct page, lru);
1952 list_del(&page->lru);
1953
Nick Piggin315e9952010-04-21 03:18:28 +00001954 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 GFP_KERNEL)) {
1956 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001957 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001958 data += PAGE_CACHE_SIZE;
1959 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 continue;
1961 }
Jeff Layton06b43672010-06-01 10:54:45 -04001962 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001964 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966 if (PAGE_CACHE_SIZE > bytes_read) {
1967 memcpy(target, data, bytes_read);
1968 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001969 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 PAGE_CACHE_SIZE - bytes_read);
1971 bytes_read = 0;
1972 } else {
1973 memcpy(target, data, PAGE_CACHE_SIZE);
1974 bytes_read -= PAGE_CACHE_SIZE;
1975 }
1976 kunmap_atomic(target, KM_USER0);
1977
1978 flush_dcache_page(page);
1979 SetPageUptodate(page);
1980 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 data += PAGE_CACHE_SIZE;
1982 }
1983 return;
1984}
1985
1986static int cifs_readpages(struct file *file, struct address_space *mapping,
1987 struct list_head *page_list, unsigned num_pages)
1988{
1989 int rc = -EACCES;
1990 int xid;
1991 loff_t offset;
1992 struct page *page;
1993 struct cifs_sb_info *cifs_sb;
1994 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001995 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001996 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 char *smb_read_data = NULL;
1998 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002000 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 xid = GetXid();
2003 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302004 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302006 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 }
2008 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002009 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002011
Steve Frenchf19159d2010-04-21 04:12:10 +00002012 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 for (i = 0; i < num_pages; ) {
2014 unsigned contig_pages;
2015 struct page *tmp_page;
2016 unsigned long expected_index;
2017
2018 if (list_empty(page_list))
2019 break;
2020
2021 page = list_entry(page_list->prev, struct page, lru);
2022 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2023
2024 /* count adjacent pages that we will read into */
2025 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002026 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002028 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 if (tmp_page->index == expected_index) {
2030 contig_pages++;
2031 expected_index++;
2032 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002033 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035 if (contig_pages + i > num_pages)
2036 contig_pages = num_pages - i;
2037
2038 /* for reads over a certain size could initiate async
2039 read ahead */
2040
2041 read_size = contig_pages * PAGE_CACHE_SIZE;
2042 /* Read size needs to be in multiples of one page */
2043 read_size = min_t(const unsigned int, read_size,
2044 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002045 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
2046 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 rc = -EAGAIN;
2048 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002049 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002051 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if (rc != 0)
2053 break;
2054 }
2055
Steve Frenchbfa0d752005-08-31 21:50:37 -07002056 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002057 open_file->netfid,
2058 read_size, offset,
2059 &bytes_read, &smb_read_data,
2060 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002061 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002062 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002064 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002065 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002067 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 smb_read_data = NULL;
2069 }
2070 }
2071 }
2072 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002073 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 break;
2075 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002076 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2078 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2079 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002080 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002083 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002084 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 i++; /* account for partial page */
2086
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002087 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002089 /* BB do we need to verify this common case ?
2090 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 we will hit it on next read */
2092
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002093 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
2095 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002096 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002097 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002098 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002099 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 break;
2102 }
2103 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002104 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002105 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002106 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002107 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 smb_read_data = NULL;
2109 }
2110 bytes_read = 0;
2111 }
2112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113/* need to free smb_read_data buf before exit */
2114 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002115 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002116 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002117 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002118 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
2122 FreeXid(xid);
2123 return rc;
2124}
2125
2126static int cifs_readpage_worker(struct file *file, struct page *page,
2127 loff_t *poffset)
2128{
2129 char *read_data;
2130 int rc;
2131
2132 page_cache_get(page);
2133 read_data = kmap(page);
2134 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002137
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 if (rc < 0)
2139 goto io_error;
2140 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002141 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002142
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002143 file->f_path.dentry->d_inode->i_atime =
2144 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 if (PAGE_CACHE_SIZE > rc)
2147 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2148
2149 flush_dcache_page(page);
2150 SetPageUptodate(page);
2151 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002154 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 page_cache_release(page);
2156 return rc;
2157}
2158
2159static int cifs_readpage(struct file *file, struct page *page)
2160{
2161 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2162 int rc = -EACCES;
2163 int xid;
2164
2165 xid = GetXid();
2166
2167 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302168 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302170 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 }
2172
Joe Perchesb6b38f72010-04-21 03:50:45 +00002173 cFYI(1, "readpage %p at offset %d 0x%x\n",
2174 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 rc = cifs_readpage_worker(file, page, &offset);
2177
2178 unlock_page(page);
2179
2180 FreeXid(xid);
2181 return rc;
2182}
2183
Steve Frencha403a0a2007-07-26 15:54:16 +00002184static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2185{
2186 struct cifsFileInfo *open_file;
2187
2188 read_lock(&GlobalSMBSeslock);
2189 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2190 if (open_file->closePend)
2191 continue;
2192 if (open_file->pfile &&
2193 ((open_file->pfile->f_flags & O_RDWR) ||
2194 (open_file->pfile->f_flags & O_WRONLY))) {
2195 read_unlock(&GlobalSMBSeslock);
2196 return 1;
2197 }
2198 }
2199 read_unlock(&GlobalSMBSeslock);
2200 return 0;
2201}
2202
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203/* We do not want to update the file size from server for inodes
2204 open for write - to avoid races with writepage extending
2205 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002206 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 but this is tricky to do without racing with writebehind
2208 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002209bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
Steve Frencha403a0a2007-07-26 15:54:16 +00002211 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002212 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002213
Steve Frencha403a0a2007-07-26 15:54:16 +00002214 if (is_inode_writable(cifsInode)) {
2215 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002216 struct cifs_sb_info *cifs_sb;
2217
Steve Frenchc32a0b62006-01-12 14:41:28 -08002218 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002219 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002220 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002221 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002222 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002223 }
2224
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002225 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002226 return true;
Steve French7ba52632007-02-08 18:14:13 +00002227
Steve French4b18f2a2008-04-29 00:06:05 +00002228 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002229 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002230 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231}
2232
Nick Piggind9414772008-09-24 11:32:59 -04002233static int cifs_write_begin(struct file *file, struct address_space *mapping,
2234 loff_t pos, unsigned len, unsigned flags,
2235 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236{
Nick Piggind9414772008-09-24 11:32:59 -04002237 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2238 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002239 loff_t page_start = pos & PAGE_MASK;
2240 loff_t i_size;
2241 struct page *page;
2242 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
Joe Perchesb6b38f72010-04-21 03:50:45 +00002244 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002245
Nick Piggin54566b22009-01-04 12:00:53 -08002246 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002247 if (!page) {
2248 rc = -ENOMEM;
2249 goto out;
2250 }
Nick Piggind9414772008-09-24 11:32:59 -04002251
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002252 if (PageUptodate(page))
2253 goto out;
Steve French8a236262007-03-06 00:31:00 +00002254
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002255 /*
2256 * If we write a full page it will be up to date, no need to read from
2257 * the server. If the write is short, we'll end up doing a sync write
2258 * instead.
2259 */
2260 if (len == PAGE_CACHE_SIZE)
2261 goto out;
2262
2263 /*
2264 * optimize away the read when we have an oplock, and we're not
2265 * expecting to use any of the data we'd be reading in. That
2266 * is, when the page lies beyond the EOF, or straddles the EOF
2267 * and the write will cover all of the existing data.
2268 */
2269 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2270 i_size = i_size_read(mapping->host);
2271 if (page_start >= i_size ||
2272 (offset == 0 && (pos + len) >= i_size)) {
2273 zero_user_segments(page, 0, offset,
2274 offset + len,
2275 PAGE_CACHE_SIZE);
2276 /*
2277 * PageChecked means that the parts of the page
2278 * to which we're not writing are considered up
2279 * to date. Once the data is copied to the
2280 * page, it can be set uptodate.
2281 */
2282 SetPageChecked(page);
2283 goto out;
2284 }
2285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Nick Piggind9414772008-09-24 11:32:59 -04002287 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002288 /*
2289 * might as well read a page, it is fast enough. If we get
2290 * an error, we don't need to return it. cifs_write_end will
2291 * do a sync write instead since PG_uptodate isn't set.
2292 */
2293 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002294 } else {
2295 /* we could try using another file handle if there is one -
2296 but how would we lock it to prevent close of that handle
2297 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002298 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002299 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002300out:
2301 *pagep = page;
2302 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303}
2304
Jeff Layton3bc303c2009-09-21 06:47:50 -04002305static void
2306cifs_oplock_break(struct slow_work *work)
2307{
2308 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2309 oplock_break);
2310 struct inode *inode = cfile->pInode;
2311 struct cifsInodeInfo *cinode = CIFS_I(inode);
2312 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2313 int rc, waitrc = 0;
2314
2315 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002316 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002317 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002318 else
Al Viro8737c932009-12-24 06:47:55 -05002319 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002320 rc = filemap_fdatawrite(inode->i_mapping);
2321 if (cinode->clientCanCacheRead == 0) {
2322 waitrc = filemap_fdatawait(inode->i_mapping);
2323 invalidate_remote_inode(inode);
2324 }
2325 if (!rc)
2326 rc = waitrc;
2327 if (rc)
2328 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002329 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002330 }
2331
2332 /*
2333 * releasing stale oplock after recent reconnect of smb session using
2334 * a now incorrect file handle is not a data integrity issue but do
2335 * not bother sending an oplock release if session to server still is
2336 * disconnected since oplock already released by the server
2337 */
2338 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2339 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2340 LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002341 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002342 }
2343}
2344
2345static int
2346cifs_oplock_break_get(struct slow_work *work)
2347{
2348 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2349 oplock_break);
2350 mntget(cfile->mnt);
2351 cifsFileInfo_get(cfile);
2352 return 0;
2353}
2354
2355static void
2356cifs_oplock_break_put(struct slow_work *work)
2357{
2358 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2359 oplock_break);
2360 mntput(cfile->mnt);
2361 cifsFileInfo_put(cfile);
2362}
2363
2364const struct slow_work_ops cifs_oplock_break_ops = {
2365 .get_ref = cifs_oplock_break_get,
2366 .put_ref = cifs_oplock_break_put,
2367 .execute = cifs_oplock_break,
2368};
2369
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002370const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 .readpage = cifs_readpage,
2372 .readpages = cifs_readpages,
2373 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002374 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002375 .write_begin = cifs_write_begin,
2376 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 .set_page_dirty = __set_page_dirty_nobuffers,
2378 /* .sync_page = cifs_sync_page, */
2379 /* .direct_IO = */
2380};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002381
2382/*
2383 * cifs_readpages requires the server to support a buffer large enough to
2384 * contain the header plus one complete page of data. Otherwise, we need
2385 * to leave cifs_readpages out of the address space operations.
2386 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002387const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002388 .readpage = cifs_readpage,
2389 .writepage = cifs_writepage,
2390 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002391 .write_begin = cifs_write_begin,
2392 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002393 .set_page_dirty = __set_page_dirty_nobuffers,
2394 /* .sync_page = cifs_sync_page, */
2395 /* .direct_IO = */
2396};