blob: 5f1f7682256b7370bf72f563fd4800cea5d200d3 [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,
111 struct cifsInodeInfo *pCifsInode,
112 struct cifsFileInfo *pCifsFile, __u32 oplock,
113 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000114{
Steve French276a74a2009-03-03 18:00:34 +0000115
Steve French276a74a2009-03-03 18:00:34 +0000116 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000117
118 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
119 if (pCifsInode == NULL) {
120 write_unlock(&GlobalSMBSeslock);
121 return -EINVAL;
122 }
123
Steve French276a74a2009-03-03 18:00:34 +0000124 if (pCifsInode->clientCanCacheRead) {
125 /* we have the inode open somewhere else
126 no need to discard cache data */
127 goto psx_client_can_cache;
128 }
129
130 /* BB FIXME need to fix this check to move it earlier into posix_open
131 BB fIX following section BB FIXME */
132
133 /* if not oplocked, invalidate inode pages if mtime or file
134 size changed */
135/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
136 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
137 (file->f_path.dentry->d_inode->i_size ==
138 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000139 cFYI(1, "inode unchanged on server");
Steve French276a74a2009-03-03 18:00:34 +0000140 } else {
141 if (file->f_path.dentry->d_inode->i_mapping) {
142 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
143 if (rc != 0)
144 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
145 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000146 cFYI(1, "invalidating remote inode since open detected it "
147 "changed");
Steve French276a74a2009-03-03 18:00:34 +0000148 invalidate_remote_inode(file->f_path.dentry->d_inode);
149 } */
150
151psx_client_can_cache:
152 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
153 pCifsInode->clientCanCacheAll = true;
154 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000155 cFYI(1, "Exclusive Oplock granted on inode %p",
156 file->f_path.dentry->d_inode);
Steve French276a74a2009-03-03 18:00:34 +0000157 } else if ((oplock & 0xF) == OPLOCK_READ)
158 pCifsInode->clientCanCacheRead = true;
159
160 /* will have to change the unlock if we reenable the
161 filemap_fdatawrite (which does not seem necessary */
162 write_unlock(&GlobalSMBSeslock);
163 return 0;
164}
165
Steve French703a3b82009-05-21 22:21:53 +0000166static struct cifsFileInfo *
167cifs_fill_filedata(struct file *file)
168{
169 struct list_head *tmp;
170 struct cifsFileInfo *pCifsFile = NULL;
171 struct cifsInodeInfo *pCifsInode = NULL;
172
173 /* search inode for this file and fill in file->private_data */
174 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
175 read_lock(&GlobalSMBSeslock);
176 list_for_each(tmp, &pCifsInode->openFileList) {
177 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
178 if ((pCifsFile->pfile == NULL) &&
179 (pCifsFile->pid == current->tgid)) {
180 /* mode set in cifs_create */
181
182 /* needed for writepage */
183 pCifsFile->pfile = file;
184 file->private_data = pCifsFile;
185 break;
186 }
187 }
188 read_unlock(&GlobalSMBSeslock);
189
190 if (file->private_data != NULL) {
191 return pCifsFile;
192 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000193 cERROR(1, "could not find file instance for "
194 "new file %p", file);
Steve French703a3b82009-05-21 22:21:53 +0000195 return NULL;
196}
197
Steve French276a74a2009-03-03 18:00:34 +0000198/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
200 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
201 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
202 char *full_path, int xid)
203{
204 struct timespec temp;
205 int rc;
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (pCifsInode->clientCanCacheRead) {
208 /* we have the inode open somewhere else
209 no need to discard cache data */
210 goto client_can_cache;
211 }
212
213 /* BB need same check in cifs_create too? */
214 /* if not oplocked, invalidate inode pages if mtime or file
215 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400216 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800217 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
218 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000220 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800222 if (file->f_path.dentry->d_inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000223 /* BB no need to lock inode until after invalidate
224 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000225 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
226 if (rc != 0)
227 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000229 cFYI(1, "invalidating remote inode since open detected it "
230 "changed");
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800231 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233
234client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000235 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 full_path, inode->i_sb, xid);
238 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800239 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000240 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000243 pCifsInode->clientCanCacheAll = true;
244 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000245 cFYI(1, "Exclusive Oplock granted on inode %p",
246 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000248 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 return rc;
251}
252
253int cifs_open(struct inode *inode, struct file *file)
254{
255 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400256 int xid;
257 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000259 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 struct cifsFileInfo *pCifsFile;
261 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 char *full_path = NULL;
263 int desiredAccess;
264 int disposition;
265 __u16 netfid;
266 FILE_ALL_INFO *buf = NULL;
267
268 xid = GetXid();
269
270 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000271 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Steve Frencha6ce4932009-04-09 01:14:32 +0000273 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000274 pCifsFile = cifs_fill_filedata(file);
275 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530276 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000277 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530278 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800281 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530283 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530285 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 }
287
Joe Perchesb6b38f72010-04-21 03:50:45 +0000288 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
289 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000290
291 if (oplockEnabled)
292 oplock = REQ_OPLOCK;
293 else
294 oplock = 0;
295
Steve French64cc2c62009-03-04 19:54:08 +0000296 if (!tcon->broken_posix_open && tcon->unix_ext &&
297 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000298 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
299 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
300 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
Steve Frenchfa588e02010-04-22 19:21:55 +0000301 oflags |= SMB_O_CREAT;
Steve French276a74a2009-03-03 18:00:34 +0000302 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400303 rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
Steve Frenchfa588e02010-04-22 19:21:55 +0000304 inode->i_sb,
305 cifs_sb->mnt_file_mode /* ignored */,
306 oflags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000307 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000308 cFYI(1, "posix open succeeded");
Steve French276a74a2009-03-03 18:00:34 +0000309 /* no need for special case handling of setting mode
310 on read only files needed here */
311
Steve French703a3b82009-05-21 22:21:53 +0000312 pCifsFile = cifs_fill_filedata(file);
Steve French276a74a2009-03-03 18:00:34 +0000313 cifs_posix_open_inode_helper(inode, file, pCifsInode,
314 pCifsFile, oplock, netfid);
315 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000316 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
317 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000318 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000319 " unexpected error on SMB posix open"
320 ", disabling posix open support."
321 " Check if server update available.",
322 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000323 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000324 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000325 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
326 (rc != -EOPNOTSUPP)) /* path not found or net err */
327 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000328 /* else fallthrough to retry open the old way on network i/o
329 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000330 }
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 desiredAccess = cifs_convert_flags(file->f_flags);
333
334/*********************************************************************
335 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000336 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000338 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * O_CREAT FILE_OPEN_IF
340 * O_CREAT | O_EXCL FILE_CREATE
341 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
342 * O_TRUNC FILE_OVERWRITE
343 * none of the above FILE_OPEN
344 *
345 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000346 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 * O_CREAT | O_TRUNC is similar but truncates the existing
348 * file rather than creating a new file as FILE_SUPERSEDE does
349 * (which uses the attributes / metadata passed in on open call)
350 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000351 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 *? and the read write flags match reasonably. O_LARGEFILE
353 *? is irrelevant because largefile support is always used
354 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
355 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
356 *********************************************************************/
357
358 disposition = cifs_get_disposition(file->f_flags);
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 /* BB pass O_SYNC flag through on file attributes .. BB */
361
362 /* Also refresh inode by passing in file_info buf returned by SMBOpen
363 and calling get_inode_info with returned buf (at least helps
364 non-Unix server case) */
365
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000366 /* BB we can not do this if this is the second open of a file
367 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
369 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
370 if (!buf) {
371 rc = -ENOMEM;
372 goto out;
373 }
Steve French5bafd762006-06-07 00:18:43 +0000374
375 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000376 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000377 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700378 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
379 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000380 else
381 rc = -EIO; /* no NT SMB support fall into legacy open below */
382
Steve Frencha9d02ad2005-08-24 23:06:05 -0700383 if (rc == -EIO) {
384 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000385 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700386 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
387 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
388 & CIFS_MOUNT_MAP_SPECIAL_CHR);
389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000391 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 goto out;
393 }
Jeff Layton3321b792009-09-25 09:53:37 -0400394
Jeff Layton086f68b2009-09-21 14:08:18 -0400395 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
396 file->f_flags);
397 file->private_data = pCifsFile;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (file->private_data == NULL) {
399 rc = -ENOMEM;
400 goto out;
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Jeff Layton3321b792009-09-25 09:53:37 -0400403 rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
404 &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000406 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 /* time to set mode which we can not set earlier due to
408 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000409 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400410 struct cifs_unix_set_info_args args = {
411 .mode = inode->i_mode,
412 .uid = NO_CHANGE_64,
413 .gid = NO_CHANGE_64,
414 .ctime = NO_CHANGE_64,
415 .atime = NO_CHANGE_64,
416 .mtime = NO_CHANGE_64,
417 .device = 0,
418 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400419 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
420 cifs_sb->local_nls,
421 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700422 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 }
424 }
425
426out:
427 kfree(buf);
428 kfree(full_path);
429 FreeXid(xid);
430 return rc;
431}
432
Adrian Bunk04187262006-06-30 18:23:04 +0200433/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434/* to server was lost */
435static int cifs_relock_file(struct cifsFileInfo *cifsFile)
436{
437 int rc = 0;
438
439/* BB list all locks open on this file and relock */
440
441 return rc;
442}
443
Steve French4b18f2a2008-04-29 00:06:05 +0000444static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400447 int xid;
448 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000450 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct cifsFileInfo *pCifsFile;
452 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000453 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 char *full_path = NULL;
455 int desiredAccess;
456 int disposition = FILE_OPEN;
457 __u16 netfid;
458
Steve Frenchad7a2922008-02-07 23:25:02 +0000459 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000461 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return -EBADF;
463
464 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400465 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000466 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400467 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530468 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530470 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
472
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800473 if (file->f_path.dentry == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000474 cERROR(1, "no valid name if dentry freed");
Steve French3a9f4622007-04-04 17:10:24 +0000475 dump_stack();
476 rc = -EBADF;
477 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
Steve French3a9f4622007-04-04 17:10:24 +0000479
480 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000481 if (inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cERROR(1, "inode not valid");
Steve French3a9f4622007-04-04 17:10:24 +0000483 dump_stack();
484 rc = -EBADF;
485 goto reopen_error_exit;
486 }
Steve French50c2f752007-07-13 00:33:32 +0000487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000489 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491/* can not grab rename sem here because various ops, including
492 those that already have the rename sem can end up causing writepage
493 to get called and if the server was down that means we end up here,
494 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800495 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000497 rc = -ENOMEM;
498reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400499 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000501 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
503
Joe Perchesb6b38f72010-04-21 03:50:45 +0000504 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
505 inode, file->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 if (oplockEnabled)
508 oplock = REQ_OPLOCK;
509 else
Steve French4b18f2a2008-04-29 00:06:05 +0000510 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Steve French7fc8f4e2009-02-23 20:43:11 +0000512 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
513 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
514 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
515 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
516 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400517 rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
Steve Frenchfa588e02010-04-22 19:21:55 +0000518 inode->i_sb,
519 cifs_sb->mnt_file_mode /* ignored */,
520 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000521 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000522 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000523 goto reopen_success;
524 }
525 /* fallthrough to retry open the old way on errors, especially
526 in the reconnect path it is important to retry hard */
527 }
528
529 desiredAccess = cifs_convert_flags(file->f_flags);
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000532 by SMBOpen and then calling get_inode_info with returned buf
533 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 and server version of file size can be stale. If we knew for sure
535 that inode was not dirty locally we could do this */
536
Steve French7fc8f4e2009-02-23 20:43:11 +0000537 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700540 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400542 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000543 cFYI(1, "cifs_open returned 0x%x", rc);
544 cFYI(1, "oplock: %d", oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000546reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000548 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400549 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 pCifsInode = CIFS_I(inode);
551 if (pCifsInode) {
552 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000553 rc = filemap_write_and_wait(inode->i_mapping);
554 if (rc != 0)
555 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 /* temporarily disable caching while we
557 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000558 pCifsInode->clientCanCacheAll = false;
559 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000560 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 rc = cifs_get_inode_info_unix(&inode,
562 full_path, inode->i_sb, xid);
563 else
564 rc = cifs_get_inode_info(&inode,
565 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000566 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 } /* else we are writing out data to server already
568 and could deadlock if we tried to flush data, and
569 since we do not know if we have data that would
570 invalidate the current end of file on the server
571 we can not go to the server to get the new inod
572 info */
573 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000574 pCifsInode->clientCanCacheAll = true;
575 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000576 cFYI(1, "Exclusive Oplock granted on inode %p",
577 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000579 pCifsInode->clientCanCacheRead = true;
580 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000582 pCifsInode->clientCanCacheRead = false;
583 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
585 cifs_relock_file(pCifsFile);
586 }
587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 kfree(full_path);
589 FreeXid(xid);
590 return rc;
591}
592
593int cifs_close(struct inode *inode, struct file *file)
594{
595 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000596 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 struct cifs_sb_info *cifs_sb;
598 struct cifsTconInfo *pTcon;
599 struct cifsFileInfo *pSMBFile =
600 (struct cifsFileInfo *)file->private_data;
601
602 xid = GetXid();
603
604 cifs_sb = CIFS_SB(inode->i_sb);
605 pTcon = cifs_sb->tcon;
606 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000607 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000608 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000609 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (pTcon) {
611 /* no sense reconnecting to close a file that is
612 already closed */
Steve French3b795212008-11-13 19:45:32 +0000613 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000614 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000615 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400616 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000617 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700618 /* Give write a better chance to get to
619 server ahead of the close. We do not
620 want to add a wait_q here as it would
621 increase the memory utilization as
622 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000623 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700624 clear the socket */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000625 cFYI(DBG2, "close delay, write pending");
Steve French23e7dd72005-10-20 13:44:56 -0700626 msleep(timeout);
627 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000628 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000629 if (!pTcon->need_reconnect &&
630 !pSMBFile->invalidHandle)
631 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000633 } else
634 write_unlock(&GlobalSMBSeslock);
635 } else
636 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000637
638 /* Delete any outstanding lock records.
639 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000640 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000641 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
642 list_del(&li->llist);
643 kfree(li);
644 }
Roland Dreier796e5662007-05-03 04:33:45 +0000645 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000646
Steve Frenchcbe04762005-04-28 22:41:05 -0700647 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 list_del(&pSMBFile->flist);
649 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700650 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400651 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 file->private_data = NULL;
653 } else
654 rc = -EBADF;
655
Steve French4efa53f2007-09-11 05:50:53 +0000656 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (list_empty(&(CIFS_I(inode)->openFileList))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000658 cFYI(1, "closing last open instance for inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 /* if the file is not open we do not know if we can cache info
660 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000661 CIFS_I(inode)->clientCanCacheRead = false;
662 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Steve French4efa53f2007-09-11 05:50:53 +0000664 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000665 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 rc = CIFS_I(inode)->write_behind_rc;
667 FreeXid(xid);
668 return rc;
669}
670
671int cifs_closedir(struct inode *inode, struct file *file)
672{
673 int rc = 0;
674 int xid;
675 struct cifsFileInfo *pCFileStruct =
676 (struct cifsFileInfo *)file->private_data;
677 char *ptmp;
678
Joe Perchesb6b38f72010-04-21 03:50:45 +0000679 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 xid = GetXid();
682
683 if (pCFileStruct) {
684 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000685 struct cifs_sb_info *cifs_sb =
686 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 pTcon = cifs_sb->tcon;
689
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "Freeing private data in close dir");
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000691 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000692 if (!pCFileStruct->srch_inf.endOfSearch &&
693 !pCFileStruct->invalidHandle) {
694 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000695 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "Closing uncompleted readdir with rc %d",
698 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 /* not much we can do if it fails anyway, ignore rc */
700 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000701 } else
702 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
704 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000705 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000707 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000708 cifs_small_buf_release(ptmp);
709 else
710 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 kfree(file->private_data);
713 file->private_data = NULL;
714 }
715 /* BB can we lock the filestruct while this is going on? */
716 FreeXid(xid);
717 return rc;
718}
719
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000720static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
721 __u64 offset, __u8 lockType)
722{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000723 struct cifsLockInfo *li =
724 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000725 if (li == NULL)
726 return -ENOMEM;
727 li->offset = offset;
728 li->length = len;
729 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000730 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000731 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000732 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000733 return 0;
734}
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
737{
738 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 __u32 numLock = 0;
740 __u32 numUnlock = 0;
741 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000742 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000744 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000745 __u16 netfid;
746 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000747 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 length = 1 + pfLock->fl_end - pfLock->fl_start;
750 rc = -EACCES;
751 xid = GetXid();
752
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000755 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000756 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000763 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000764 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
766 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000767 cFYI(1, "Process suspended by mandatory locking - "
768 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000770 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000771 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000773 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000776 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 numLock = 1;
778 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000779 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000781 /* Check if unlock includes more than
782 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000784 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 lockType |= LOCKING_ANDX_SHARED_LOCK;
786 numLock = 1;
787 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000788 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 numLock = 1;
790 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000791 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 lockType |= LOCKING_ANDX_SHARED_LOCK;
793 numLock = 1;
794 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000795 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800797 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000798 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530801 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530803 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
Steve French08547b02006-02-28 22:39:25 +0000805 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Steve French13a6e422008-12-02 17:24:33 +0000807 if ((tcon->ses->capabilities & CAP_UNIX) &&
808 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000809 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000810 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000811 /* BB add code here to normalize offset and length to
812 account for negative length which we can not accept over the
813 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000815 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000816 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000817 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000818 posix_lock_type = CIFS_RDLCK;
819 else
820 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000821 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000822 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000823 posix_lock_type, wait_flag);
824 FreeXid(xid);
825 return rc;
826 }
827
828 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000829 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000830 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000832 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 pfLock->fl_start, 1 /* numUnlock */ ,
834 0 /* numLock */ , lockType,
835 0 /* wait flag */ );
836 pfLock->fl_type = F_UNLCK;
837 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000838 cERROR(1, "Error unlocking previously locked "
839 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 rc = 0;
841
842 } else {
843 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400844 rc = 0;
845
846 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
847 pfLock->fl_type = F_WRLCK;
848 } else {
849 rc = CIFSSMBLock(xid, tcon, netfid, length,
850 pfLock->fl_start, 0, 1,
851 lockType | LOCKING_ANDX_SHARED_LOCK,
852 0 /* wait flag */);
853 if (rc == 0) {
854 rc = CIFSSMBLock(xid, tcon, netfid,
855 length, pfLock->fl_start, 1, 0,
856 lockType |
857 LOCKING_ANDX_SHARED_LOCK,
858 0 /* wait flag */);
859 pfLock->fl_type = F_RDLCK;
860 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000861 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400862 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000863 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400864 rc = 0;
865 } else {
866 pfLock->fl_type = F_WRLCK;
867 rc = 0;
868 }
869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871
872 FreeXid(xid);
873 return rc;
874 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000875
876 if (!numLock && !numUnlock) {
877 /* if no lock or unlock then nothing
878 to do since we do not know what it is */
879 FreeXid(xid);
880 return -EOPNOTSUPP;
881 }
882
883 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000884 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000885 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000886 posix_lock_type = CIFS_RDLCK;
887 else
888 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000889
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000890 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000891 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000892
Steve French13a6e422008-12-02 17:24:33 +0000893 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000894 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000895 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000897 struct cifsFileInfo *fid =
898 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000899
900 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000901 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000903 0, numLock, lockType, wait_flag);
904
905 if (rc == 0) {
906 /* For Windows locks we must store them. */
907 rc = store_file_lock(fid, length,
908 pfLock->fl_start, lockType);
909 }
910 } else if (numUnlock) {
911 /* For each stored lock that this unlock overlaps
912 completely, unlock it. */
913 int stored_rc = 0;
914 struct cifsLockInfo *li, *tmp;
915
Steve French6b70c952006-09-21 07:35:29 +0000916 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000917 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000918 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
919 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000920 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000921 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000922 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000923 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000925 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000926 if (stored_rc)
927 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000928 else {
929 list_del(&li->llist);
930 kfree(li);
931 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 }
933 }
Roland Dreier796e5662007-05-03 04:33:45 +0000934 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000935 }
936 }
937
Steve Frenchd634cc12005-08-26 14:42:59 -0500938 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 posix_lock_file_wait(file, pfLock);
940 FreeXid(xid);
941 return rc;
942}
943
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400944/*
945 * Set the timeout on write requests past EOF. For some servers (Windows)
946 * these calls can be very long.
947 *
948 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
949 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
950 * The 10M cutoff is totally arbitrary. A better scheme for this would be
951 * welcome if someone wants to suggest one.
952 *
953 * We may be able to do a better job with this if there were some way to
954 * declare that a file should be sparse.
955 */
956static int
957cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
958{
959 if (offset <= cifsi->server_eof)
960 return CIFS_STD_OP;
961 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
962 return CIFS_VLONG_OP;
963 else
964 return CIFS_LONG_OP;
965}
966
967/* update the file size (if needed) after a write */
968static void
969cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
970 unsigned int bytes_written)
971{
972 loff_t end_of_write = offset + bytes_written;
973
974 if (end_of_write > cifsi->server_eof)
975 cifsi->server_eof = end_of_write;
976}
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978ssize_t cifs_user_write(struct file *file, const char __user *write_data,
979 size_t write_size, loff_t *poffset)
980{
981 int rc = 0;
982 unsigned int bytes_written = 0;
983 unsigned int total_written;
984 struct cifs_sb_info *cifs_sb;
985 struct cifsTconInfo *pTcon;
986 int xid, long_op;
987 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400988 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800990 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 pTcon = cifs_sb->tcon;
993
Joe Perchesb6b38f72010-04-21 03:50:45 +0000994 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
995 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 if (file->private_data == NULL)
998 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000999 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001000
Jeff Layton838726c2008-08-28 07:54:59 -04001001 rc = generic_write_checks(file, poffset, &write_size, 0);
1002 if (rc)
1003 return rc;
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001007 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 for (total_written = 0; write_size > total_written;
1009 total_written += bytes_written) {
1010 rc = -EAGAIN;
1011 while (rc == -EAGAIN) {
1012 if (file->private_data == NULL) {
1013 /* file has been closed on us */
1014 FreeXid(xid);
1015 /* if we have gotten here we have written some data
1016 and blocked, and the file has been freed on us while
1017 we blocked so return what we managed to write */
1018 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (open_file->closePend) {
1021 FreeXid(xid);
1022 if (total_written)
1023 return total_written;
1024 else
1025 return -EBADF;
1026 }
1027 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 /* we could deadlock if we called
1029 filemap_fdatawait from here so tell
1030 reopen_file not to flush data to server
1031 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001032 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (rc != 0)
1034 break;
1035 }
1036
1037 rc = CIFSSMBWrite(xid, pTcon,
1038 open_file->netfid,
1039 min_t(const int, cifs_sb->wsize,
1040 write_size - total_written),
1041 *poffset, &bytes_written,
1042 NULL, write_data + total_written, long_op);
1043 }
1044 if (rc || (bytes_written == 0)) {
1045 if (total_written)
1046 break;
1047 else {
1048 FreeXid(xid);
1049 return rc;
1050 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001051 } else {
1052 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001054 }
Steve French133672e2007-11-13 22:41:37 +00001055 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 15 seconds is plenty */
1057 }
1058
Steve Frencha4544342005-08-24 13:59:35 -07001059 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001062 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1063 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001064/* Do not update local mtime - server will set its actual value on write
1065 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001066 * current_fs_time(inode->i_sb);*/
1067 if (total_written > 0) {
1068 spin_lock(&inode->i_lock);
1069 if (*poffset > file->f_path.dentry->d_inode->i_size)
1070 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001072 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001074 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 }
1076 FreeXid(xid);
1077 return total_written;
1078}
1079
1080static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001081 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082{
1083 int rc = 0;
1084 unsigned int bytes_written = 0;
1085 unsigned int total_written;
1086 struct cifs_sb_info *cifs_sb;
1087 struct cifsTconInfo *pTcon;
1088 int xid, long_op;
1089 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001090 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001092 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 pTcon = cifs_sb->tcon;
1095
Joe Perchesb6b38f72010-04-21 03:50:45 +00001096 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
1097 *poffset, file->f_path.dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (file->private_data == NULL)
1100 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001101 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001105 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 for (total_written = 0; write_size > total_written;
1107 total_written += bytes_written) {
1108 rc = -EAGAIN;
1109 while (rc == -EAGAIN) {
1110 if (file->private_data == NULL) {
1111 /* file has been closed on us */
1112 FreeXid(xid);
1113 /* if we have gotten here we have written some data
1114 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001115 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 write */
1117 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 if (open_file->closePend) {
1120 FreeXid(xid);
1121 if (total_written)
1122 return total_written;
1123 else
1124 return -EBADF;
1125 }
1126 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 /* we could deadlock if we called
1128 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001129 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001131 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (rc != 0)
1133 break;
1134 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001135 if (experimEnabled || (pTcon->ses->server &&
1136 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001137 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001138 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001139 struct kvec iov[2];
1140 unsigned int len;
1141
Steve French0ae0efa2005-10-10 10:57:19 -07001142 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001143 write_size - total_written);
1144 /* iov[0] is reserved for smb header */
1145 iov[1].iov_base = (char *)write_data +
1146 total_written;
1147 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001148 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001149 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001150 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001151 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001152 } else
Steve French60808232006-04-22 15:53:05 +00001153 rc = CIFSSMBWrite(xid, pTcon,
1154 open_file->netfid,
1155 min_t(const int, cifs_sb->wsize,
1156 write_size - total_written),
1157 *poffset, &bytes_written,
1158 write_data + total_written,
1159 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161 if (rc || (bytes_written == 0)) {
1162 if (total_written)
1163 break;
1164 else {
1165 FreeXid(xid);
1166 return rc;
1167 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001168 } else {
1169 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001171 }
Steve French133672e2007-11-13 22:41:37 +00001172 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 15 seconds is plenty */
1174 }
1175
Steve Frencha4544342005-08-24 13:59:35 -07001176 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001179 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001180/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001181/* file->f_path.dentry->d_inode->i_ctime =
1182 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1183 if (total_written > 0) {
1184 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1185 if (*poffset > file->f_path.dentry->d_inode->i_size)
1186 i_size_write(file->f_path.dentry->d_inode,
1187 *poffset);
1188 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
Steve French3677db12007-02-26 16:46:11 +00001190 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192 FreeXid(xid);
1193 return total_written;
1194}
1195
Steve French630f3f0c2007-10-25 21:17:17 +00001196#ifdef CONFIG_CIFS_EXPERIMENTAL
1197struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1198{
1199 struct cifsFileInfo *open_file = NULL;
1200
1201 read_lock(&GlobalSMBSeslock);
1202 /* we could simply get the first_list_entry since write-only entries
1203 are always at the end of the list but since the first entry might
1204 have a close pending, we go through the whole list */
1205 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1206 if (open_file->closePend)
1207 continue;
1208 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1209 (open_file->pfile->f_flags & O_RDONLY))) {
1210 if (!open_file->invalidHandle) {
1211 /* found a good file */
1212 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001213 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001214 read_unlock(&GlobalSMBSeslock);
1215 return open_file;
1216 } /* else might as well continue, and look for
1217 another, or simply have the caller reopen it
1218 again rather than trying to fix this handle */
1219 } else /* write only file */
1220 break; /* write only files are last so must be done */
1221 }
1222 read_unlock(&GlobalSMBSeslock);
1223 return NULL;
1224}
1225#endif
1226
Steve Frenchdd99cd82005-10-05 19:32:49 -07001227struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001228{
1229 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001230 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001231 int rc;
Steve French6148a742005-10-05 12:23:19 -07001232
Steve French60808232006-04-22 15:53:05 +00001233 /* Having a null inode here (because mapping->host was set to zero by
1234 the VFS or MM) should not happen but we had reports of on oops (due to
1235 it being zero) during stress testcases so we need to check for it */
1236
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001237 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001238 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001239 dump_stack();
1240 return NULL;
1241 }
1242
Steve French6148a742005-10-05 12:23:19 -07001243 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001244refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001245 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001246 if (open_file->closePend ||
1247 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001248 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001249
Steve French6148a742005-10-05 12:23:19 -07001250 if (open_file->pfile &&
1251 ((open_file->pfile->f_flags & O_RDWR) ||
1252 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001253 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001254
1255 if (!open_file->invalidHandle) {
1256 /* found a good writable file */
1257 read_unlock(&GlobalSMBSeslock);
1258 return open_file;
1259 }
Steve French8840dee2007-11-16 23:05:52 +00001260
Steve French6148a742005-10-05 12:23:19 -07001261 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001262 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001263 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001264 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001265 if (!open_file->closePend)
1266 return open_file;
1267 else { /* start over in case this was deleted */
1268 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001269 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001270 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001271 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001272 }
1273 }
Steve French9b22b0b2007-10-02 01:11:08 +00001274
1275 /* if it fails, try another handle if possible -
1276 (we can not do this if closePending since
1277 loop could be modified - in which case we
1278 have to start at the beginning of the list
1279 again. Note that it would be bad
1280 to hold up writepages here (rather than
1281 in caller) with continuous retries */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001282 cFYI(1, "wp failed on reopen file");
Steve French9b22b0b2007-10-02 01:11:08 +00001283 read_lock(&GlobalSMBSeslock);
1284 /* can not use this handle, no write
1285 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001286 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001287
Steve French9b22b0b2007-10-02 01:11:08 +00001288 if (open_file->closePend) /* list could have changed */
1289 goto refind_writable;
1290 /* else we simply continue to the next entry. Thus
1291 we do not loop on reopen errors. If we
1292 can not reopen the file, for example if we
1293 reconnected to a server with another client
1294 racing to delete or lock the file we would not
1295 make progress if we restarted before the beginning
1296 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001297 }
1298 }
Jeff Layton2846d382008-09-22 21:33:33 -04001299 /* couldn't find useable FH with same pid, try any available */
1300 if (!any_available) {
1301 any_available = true;
1302 goto refind_writable;
1303 }
Steve French6148a742005-10-05 12:23:19 -07001304 read_unlock(&GlobalSMBSeslock);
1305 return NULL;
1306}
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1309{
1310 struct address_space *mapping = page->mapping;
1311 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1312 char *write_data;
1313 int rc = -EFAULT;
1314 int bytes_written = 0;
1315 struct cifs_sb_info *cifs_sb;
1316 struct cifsTconInfo *pTcon;
1317 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001318 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 if (!mapping || !mapping->host)
1321 return -EFAULT;
1322
1323 inode = page->mapping->host;
1324 cifs_sb = CIFS_SB(inode->i_sb);
1325 pTcon = cifs_sb->tcon;
1326
1327 offset += (loff_t)from;
1328 write_data = kmap(page);
1329 write_data += from;
1330
1331 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1332 kunmap(page);
1333 return -EIO;
1334 }
1335
1336 /* racing with truncate? */
1337 if (offset > mapping->host->i_size) {
1338 kunmap(page);
1339 return 0; /* don't care */
1340 }
1341
1342 /* check to make sure that we are not extending the file */
1343 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001344 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Steve French6148a742005-10-05 12:23:19 -07001346 open_file = find_writable_file(CIFS_I(mapping->host));
1347 if (open_file) {
1348 bytes_written = cifs_write(open_file->pfile, write_data,
1349 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001350 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001352 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001353 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001354 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001355 else if (bytes_written < 0)
1356 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001357 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001358 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 rc = -EIO;
1360 }
1361
1362 kunmap(page);
1363 return rc;
1364}
1365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001367 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368{
Steve French37c0eb42005-10-05 14:50:29 -07001369 struct backing_dev_info *bdi = mapping->backing_dev_info;
1370 unsigned int bytes_to_write;
1371 unsigned int bytes_written;
1372 struct cifs_sb_info *cifs_sb;
1373 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001374 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001375 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001376 int range_whole = 0;
1377 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001378 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001379 int n_iov = 0;
1380 pgoff_t next;
1381 int nr_pages;
1382 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001383 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001384 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001385 struct page *page;
1386 struct pagevec pvec;
1387 int rc = 0;
1388 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001389 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Steve French37c0eb42005-10-05 14:50:29 -07001391 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001392
Steve French37c0eb42005-10-05 14:50:29 -07001393 /*
1394 * If wsize is smaller that the page cache size, default to writing
1395 * one page at a time via cifs_writepage
1396 */
1397 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1398 return generic_writepages(mapping, wbc);
1399
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001400 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1401 if (cifs_sb->tcon->ses->server->secMode &
1402 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1403 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001404 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001405
Steve French9a0c8232007-02-02 04:21:57 +00001406 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001407 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001408 return generic_writepages(mapping, wbc);
1409
1410
Steve French37c0eb42005-10-05 14:50:29 -07001411 /*
1412 * BB: Is this meaningful for a non-block-device file system?
1413 * If it is, we should test it again after we do I/O
1414 */
1415 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1416 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001417 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001418 return 0;
1419 }
1420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 xid = GetXid();
1422
Steve French37c0eb42005-10-05 14:50:29 -07001423 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001424 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001425 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001426 end = -1;
1427 } else {
1428 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1429 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1430 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1431 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001432 scanned = 1;
1433 }
1434retry:
1435 while (!done && (index <= end) &&
1436 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1437 PAGECACHE_TAG_DIRTY,
1438 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1439 int first;
1440 unsigned int i;
1441
Steve French37c0eb42005-10-05 14:50:29 -07001442 first = -1;
1443 next = 0;
1444 n_iov = 0;
1445 bytes_to_write = 0;
1446
1447 for (i = 0; i < nr_pages; i++) {
1448 page = pvec.pages[i];
1449 /*
1450 * At this point we hold neither mapping->tree_lock nor
1451 * lock on the page itself: the page may be truncated or
1452 * invalidated (changing page->mapping to NULL), or even
1453 * swizzled back from swapper_space to tmpfs file
1454 * mapping
1455 */
1456
1457 if (first < 0)
1458 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001459 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001460 break;
1461
1462 if (unlikely(page->mapping != mapping)) {
1463 unlock_page(page);
1464 break;
1465 }
1466
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001467 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001468 done = 1;
1469 unlock_page(page);
1470 break;
1471 }
1472
1473 if (next && (page->index != next)) {
1474 /* Not next consecutive page */
1475 unlock_page(page);
1476 break;
1477 }
1478
1479 if (wbc->sync_mode != WB_SYNC_NONE)
1480 wait_on_page_writeback(page);
1481
1482 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001483 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001484 unlock_page(page);
1485 break;
1486 }
Steve French84d2f072005-10-12 15:32:05 -07001487
Linus Torvaldscb876f42006-12-23 16:19:07 -08001488 /*
1489 * This actually clears the dirty bit in the radix tree.
1490 * See cifs_writepage() for more commentary.
1491 */
1492 set_page_writeback(page);
1493
Steve French84d2f072005-10-12 15:32:05 -07001494 if (page_offset(page) >= mapping->host->i_size) {
1495 done = 1;
1496 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001497 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001498 break;
1499 }
1500
Steve French37c0eb42005-10-05 14:50:29 -07001501 /*
1502 * BB can we get rid of this? pages are held by pvec
1503 */
1504 page_cache_get(page);
1505
Steve French84d2f072005-10-12 15:32:05 -07001506 len = min(mapping->host->i_size - page_offset(page),
1507 (loff_t)PAGE_CACHE_SIZE);
1508
Steve French37c0eb42005-10-05 14:50:29 -07001509 /* reserve iov[0] for the smb header */
1510 n_iov++;
1511 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001512 iov[n_iov].iov_len = len;
1513 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001514
1515 if (first < 0) {
1516 first = i;
1517 offset = page_offset(page);
1518 }
1519 next = page->index + 1;
1520 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1521 break;
1522 }
1523 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001524 /* Search for a writable handle every time we call
1525 * CIFSSMBWrite2. We can't rely on the last handle
1526 * we used to still be valid
1527 */
1528 open_file = find_writable_file(CIFS_I(mapping->host));
1529 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001530 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001531 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001532 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001533 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001534 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1535 open_file->netfid,
1536 bytes_to_write, offset,
1537 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001538 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001539 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001540 cifs_update_eof(cifsi, offset, bytes_written);
1541
Steve French23e7dd72005-10-20 13:44:56 -07001542 if (rc || bytes_written < bytes_to_write) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001543 cERROR(1, "Write2 ret %d, wrote %d",
1544 rc, bytes_written);
Steve French23e7dd72005-10-20 13:44:56 -07001545 /* BB what if continued retry is
1546 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001547 if (rc == -ENOSPC)
1548 set_bit(AS_ENOSPC, &mapping->flags);
1549 else
1550 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001551 } else {
1552 cifs_stats_bytes_written(cifs_sb->tcon,
1553 bytes_written);
1554 }
Steve French37c0eb42005-10-05 14:50:29 -07001555 }
1556 for (i = 0; i < n_iov; i++) {
1557 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001558 /* Should we also set page error on
1559 success rc but too little data written? */
1560 /* BB investigate retry logic on temporary
1561 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001562 when page marked as error */
1563 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001564 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001565 kunmap(page);
1566 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001567 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001568 page_cache_release(page);
1569 }
1570 if ((wbc->nr_to_write -= n_iov) <= 0)
1571 done = 1;
1572 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001573 } else
1574 /* Need to re-find the pages we skipped */
1575 index = pvec.pages[0]->index + 1;
1576
Steve French37c0eb42005-10-05 14:50:29 -07001577 pagevec_release(&pvec);
1578 }
1579 if (!scanned && !done) {
1580 /*
1581 * We hit the last page and there is more work to be done: wrap
1582 * back to the start of the file
1583 */
1584 scanned = 1;
1585 index = 0;
1586 goto retry;
1587 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001588 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001589 mapping->writeback_index = index;
1590
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001592 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 return rc;
1594}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001596static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
1598 int rc = -EFAULT;
1599 int xid;
1600
1601 xid = GetXid();
1602/* BB add check for wbc flags */
1603 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001604 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001605 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001606
1607 /*
1608 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1609 *
1610 * A writepage() implementation always needs to do either this,
1611 * or re-dirty the page with "redirty_page_for_writepage()" in
1612 * the case of a failure.
1613 *
1614 * Just unlocking the page will cause the radix tree tag-bits
1615 * to fail to update with the state of the page correctly.
1616 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001617 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1619 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1620 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001621 end_page_writeback(page);
1622 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 FreeXid(xid);
1624 return rc;
1625}
1626
Nick Piggind9414772008-09-24 11:32:59 -04001627static int cifs_write_end(struct file *file, struct address_space *mapping,
1628 loff_t pos, unsigned len, unsigned copied,
1629 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630{
Nick Piggind9414772008-09-24 11:32:59 -04001631 int rc;
1632 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Joe Perchesb6b38f72010-04-21 03:50:45 +00001634 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1635 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001636
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001637 if (PageChecked(page)) {
1638 if (copied == len)
1639 SetPageUptodate(page);
1640 ClearPageChecked(page);
1641 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001642 SetPageUptodate(page);
1643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001645 char *page_data;
1646 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1647 int xid;
1648
1649 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 /* this is probably better than directly calling
1651 partialpage_write since in this function the file handle is
1652 known which we might as well leverage */
1653 /* BB check if anything else missing out of ppw
1654 such as updating last write time */
1655 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001656 rc = cifs_write(file, page_data + offset, copied, &pos);
1657 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001659
1660 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001661 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001662 rc = copied;
1663 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 set_page_dirty(page);
1665 }
1666
Nick Piggind9414772008-09-24 11:32:59 -04001667 if (rc > 0) {
1668 spin_lock(&inode->i_lock);
1669 if (pos > inode->i_size)
1670 i_size_write(inode, pos);
1671 spin_unlock(&inode->i_lock);
1672 }
1673
1674 unlock_page(page);
1675 page_cache_release(page);
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 return rc;
1678}
1679
1680int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1681{
1682 int xid;
1683 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001684 struct cifsTconInfo *tcon;
1685 struct cifsFileInfo *smbfile =
1686 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001687 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
1689 xid = GetXid();
1690
Joe Perchesb6b38f72010-04-21 03:50:45 +00001691 cFYI(1, "Sync file - name: %s datasync: 0x%x",
1692 dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001693
Jeff Laytoncea21802007-11-20 23:19:03 +00001694 rc = filemap_write_and_wait(inode->i_mapping);
1695 if (rc == 0) {
1696 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001698 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001699 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001700 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001701 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001702 }
Steve Frenchb298f222009-02-21 21:17:43 +00001703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 FreeXid(xid);
1705 return rc;
1706}
1707
NeilBrown3978d7172006-03-26 01:37:17 -08001708/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709{
1710 struct address_space *mapping;
1711 struct inode *inode;
1712 unsigned long index = page->index;
1713 unsigned int rpages = 0;
1714 int rc = 0;
1715
Steve Frenchf19159d2010-04-21 04:12:10 +00001716 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 mapping = page->mapping;
1718 if (!mapping)
1719 return 0;
1720 inode = mapping->host;
1721 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001722 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001724/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1726
Joe Perchesb6b38f72010-04-21 03:50:45 +00001727/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
NeilBrown3978d7172006-03-26 01:37:17 -08001729#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 if (rc < 0)
1731 return rc;
1732 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001733#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734} */
1735
1736/*
1737 * As file closes, flush all cached write data for this inode checking
1738 * for write behind errors.
1739 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001740int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001742 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 int rc = 0;
1744
1745 /* Rather than do the steps manually:
1746 lock the inode for writing
1747 loop through pages looking for write behind data (dirty pages)
1748 coalesce into contiguous 16K (or smaller) chunks to write to server
1749 send to server (prefer in parallel)
1750 deal with writebehind errors
1751 unlock inode for writing
1752 filemapfdatawrite appears easier for the time being */
1753
1754 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001755 /* reset wb rc if we were able to write out dirty pages */
1756 if (!rc) {
1757 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001759 }
Steve French50c2f752007-07-13 00:33:32 +00001760
Joe Perchesb6b38f72010-04-21 03:50:45 +00001761 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
1763 return rc;
1764}
1765
1766ssize_t cifs_user_read(struct file *file, char __user *read_data,
1767 size_t read_size, loff_t *poffset)
1768{
1769 int rc = -EACCES;
1770 unsigned int bytes_read = 0;
1771 unsigned int total_read = 0;
1772 unsigned int current_read_size;
1773 struct cifs_sb_info *cifs_sb;
1774 struct cifsTconInfo *pTcon;
1775 int xid;
1776 struct cifsFileInfo *open_file;
1777 char *smb_read_data;
1778 char __user *current_offset;
1779 struct smb_com_read_rsp *pSMBr;
1780
1781 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001782 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 pTcon = cifs_sb->tcon;
1784
1785 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301786 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301788 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 }
1790 open_file = (struct cifsFileInfo *)file->private_data;
1791
Steve Frenchad7a2922008-02-07 23:25:02 +00001792 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001793 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 for (total_read = 0, current_offset = read_data;
1796 read_size > total_read;
1797 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001798 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 cifs_sb->rsize);
1800 rc = -EAGAIN;
1801 smb_read_data = NULL;
1802 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001803 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001806 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 if (rc != 0)
1808 break;
1809 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001810 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001811 open_file->netfid,
1812 current_read_size, *poffset,
1813 &bytes_read, &smb_read_data,
1814 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001817 if (copy_to_user(current_offset,
1818 smb_read_data +
1819 4 /* RFC1001 length field */ +
1820 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001821 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001822 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001823
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001824 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001825 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001826 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001827 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 smb_read_data = NULL;
1829 }
1830 }
1831 if (rc || (bytes_read == 0)) {
1832 if (total_read) {
1833 break;
1834 } else {
1835 FreeXid(xid);
1836 return rc;
1837 }
1838 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001839 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 *poffset += bytes_read;
1841 }
1842 }
1843 FreeXid(xid);
1844 return total_read;
1845}
1846
1847
1848static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1849 loff_t *poffset)
1850{
1851 int rc = -EACCES;
1852 unsigned int bytes_read = 0;
1853 unsigned int total_read;
1854 unsigned int current_read_size;
1855 struct cifs_sb_info *cifs_sb;
1856 struct cifsTconInfo *pTcon;
1857 int xid;
1858 char *current_offset;
1859 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001860 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001863 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 pTcon = cifs_sb->tcon;
1865
1866 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301867 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301869 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 }
1871 open_file = (struct cifsFileInfo *)file->private_data;
1872
1873 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001874 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001876 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 read_size > total_read;
1878 total_read += bytes_read, current_offset += bytes_read) {
1879 current_read_size = min_t(const int, read_size - total_read,
1880 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001881 /* For windows me and 9x we do not want to request more
1882 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001883 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001884 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1885 current_read_size = min_t(const int, current_read_size,
1886 pTcon->ses->server->maxBuf - 128);
1887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 rc = -EAGAIN;
1889 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001890 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001892 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 if (rc != 0)
1894 break;
1895 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001896 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001897 open_file->netfid,
1898 current_read_size, *poffset,
1899 &bytes_read, &current_offset,
1900 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
1902 if (rc || (bytes_read == 0)) {
1903 if (total_read) {
1904 break;
1905 } else {
1906 FreeXid(xid);
1907 return rc;
1908 }
1909 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001910 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 *poffset += bytes_read;
1912 }
1913 }
1914 FreeXid(xid);
1915 return total_read;
1916}
1917
1918int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1919{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 int rc, xid;
1921
1922 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001923 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001925 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 FreeXid(xid);
1927 return rc;
1928 }
1929 rc = generic_file_mmap(file, vma);
1930 FreeXid(xid);
1931 return rc;
1932}
1933
1934
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001935static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001936 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937{
1938 struct page *page;
1939 char *target;
1940
1941 while (bytes_read > 0) {
1942 if (list_empty(pages))
1943 break;
1944
1945 page = list_entry(pages->prev, struct page, lru);
1946 list_del(&page->lru);
1947
Nick Piggin315e9952010-04-21 03:18:28 +00001948 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 GFP_KERNEL)) {
1950 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001951 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001952 data += PAGE_CACHE_SIZE;
1953 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 continue;
1955 }
1956
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001957 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 if (PAGE_CACHE_SIZE > bytes_read) {
1960 memcpy(target, data, bytes_read);
1961 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001962 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 PAGE_CACHE_SIZE - bytes_read);
1964 bytes_read = 0;
1965 } else {
1966 memcpy(target, data, PAGE_CACHE_SIZE);
1967 bytes_read -= PAGE_CACHE_SIZE;
1968 }
1969 kunmap_atomic(target, KM_USER0);
1970
1971 flush_dcache_page(page);
1972 SetPageUptodate(page);
1973 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 data += PAGE_CACHE_SIZE;
1975 }
1976 return;
1977}
1978
1979static int cifs_readpages(struct file *file, struct address_space *mapping,
1980 struct list_head *page_list, unsigned num_pages)
1981{
1982 int rc = -EACCES;
1983 int xid;
1984 loff_t offset;
1985 struct page *page;
1986 struct cifs_sb_info *cifs_sb;
1987 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001988 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 char *smb_read_data = NULL;
1991 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001993 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
1995 xid = GetXid();
1996 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301997 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301999 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 }
2001 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002002 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002004
Steve Frenchf19159d2010-04-21 04:12:10 +00002005 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 for (i = 0; i < num_pages; ) {
2007 unsigned contig_pages;
2008 struct page *tmp_page;
2009 unsigned long expected_index;
2010
2011 if (list_empty(page_list))
2012 break;
2013
2014 page = list_entry(page_list->prev, struct page, lru);
2015 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2016
2017 /* count adjacent pages that we will read into */
2018 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002019 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002021 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 if (tmp_page->index == expected_index) {
2023 contig_pages++;
2024 expected_index++;
2025 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002026 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 }
2028 if (contig_pages + i > num_pages)
2029 contig_pages = num_pages - i;
2030
2031 /* for reads over a certain size could initiate async
2032 read ahead */
2033
2034 read_size = contig_pages * PAGE_CACHE_SIZE;
2035 /* Read size needs to be in multiples of one page */
2036 read_size = min_t(const unsigned int, read_size,
2037 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002038 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
2039 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 rc = -EAGAIN;
2041 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002042 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002044 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 if (rc != 0)
2046 break;
2047 }
2048
Steve Frenchbfa0d752005-08-31 21:50:37 -07002049 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002050 open_file->netfid,
2051 read_size, offset,
2052 &bytes_read, &smb_read_data,
2053 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002054 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002055 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002058 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002060 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 smb_read_data = NULL;
2062 }
2063 }
2064 }
2065 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002066 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 break;
2068 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002069 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2071 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2072 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002073 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
2075 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002076 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002077 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 i++; /* account for partial page */
2079
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002080 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002082 /* BB do we need to verify this common case ?
2083 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 we will hit it on next read */
2085
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002086 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 }
2088 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002089 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002090 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002091 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 break;
2095 }
2096 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002097 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002098 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002099 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002100 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 smb_read_data = NULL;
2102 }
2103 bytes_read = 0;
2104 }
2105
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106/* need to free smb_read_data buf before exit */
2107 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002108 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002109 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002111 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115 FreeXid(xid);
2116 return rc;
2117}
2118
2119static int cifs_readpage_worker(struct file *file, struct page *page,
2120 loff_t *poffset)
2121{
2122 char *read_data;
2123 int rc;
2124
2125 page_cache_get(page);
2126 read_data = kmap(page);
2127 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 if (rc < 0)
2132 goto io_error;
2133 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002134 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002135
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002136 file->f_path.dentry->d_inode->i_atime =
2137 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002138
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 if (PAGE_CACHE_SIZE > rc)
2140 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2141
2142 flush_dcache_page(page);
2143 SetPageUptodate(page);
2144 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002147 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 page_cache_release(page);
2149 return rc;
2150}
2151
2152static int cifs_readpage(struct file *file, struct page *page)
2153{
2154 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2155 int rc = -EACCES;
2156 int xid;
2157
2158 xid = GetXid();
2159
2160 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302161 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302163 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 }
2165
Joe Perchesb6b38f72010-04-21 03:50:45 +00002166 cFYI(1, "readpage %p at offset %d 0x%x\n",
2167 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169 rc = cifs_readpage_worker(file, page, &offset);
2170
2171 unlock_page(page);
2172
2173 FreeXid(xid);
2174 return rc;
2175}
2176
Steve Frencha403a0a2007-07-26 15:54:16 +00002177static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2178{
2179 struct cifsFileInfo *open_file;
2180
2181 read_lock(&GlobalSMBSeslock);
2182 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2183 if (open_file->closePend)
2184 continue;
2185 if (open_file->pfile &&
2186 ((open_file->pfile->f_flags & O_RDWR) ||
2187 (open_file->pfile->f_flags & O_WRONLY))) {
2188 read_unlock(&GlobalSMBSeslock);
2189 return 1;
2190 }
2191 }
2192 read_unlock(&GlobalSMBSeslock);
2193 return 0;
2194}
2195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196/* We do not want to update the file size from server for inodes
2197 open for write - to avoid races with writepage extending
2198 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002199 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 but this is tricky to do without racing with writebehind
2201 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002202bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203{
Steve Frencha403a0a2007-07-26 15:54:16 +00002204 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002205 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002206
Steve Frencha403a0a2007-07-26 15:54:16 +00002207 if (is_inode_writable(cifsInode)) {
2208 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002209 struct cifs_sb_info *cifs_sb;
2210
Steve Frenchc32a0b62006-01-12 14:41:28 -08002211 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002212 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002213 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002214 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002215 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002216 }
2217
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002218 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002219 return true;
Steve French7ba52632007-02-08 18:14:13 +00002220
Steve French4b18f2a2008-04-29 00:06:05 +00002221 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002222 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002223 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224}
2225
Nick Piggind9414772008-09-24 11:32:59 -04002226static int cifs_write_begin(struct file *file, struct address_space *mapping,
2227 loff_t pos, unsigned len, unsigned flags,
2228 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229{
Nick Piggind9414772008-09-24 11:32:59 -04002230 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2231 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002232 loff_t page_start = pos & PAGE_MASK;
2233 loff_t i_size;
2234 struct page *page;
2235 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Joe Perchesb6b38f72010-04-21 03:50:45 +00002237 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002238
Nick Piggin54566b22009-01-04 12:00:53 -08002239 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002240 if (!page) {
2241 rc = -ENOMEM;
2242 goto out;
2243 }
Nick Piggind9414772008-09-24 11:32:59 -04002244
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002245 if (PageUptodate(page))
2246 goto out;
Steve French8a236262007-03-06 00:31:00 +00002247
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002248 /*
2249 * If we write a full page it will be up to date, no need to read from
2250 * the server. If the write is short, we'll end up doing a sync write
2251 * instead.
2252 */
2253 if (len == PAGE_CACHE_SIZE)
2254 goto out;
2255
2256 /*
2257 * optimize away the read when we have an oplock, and we're not
2258 * expecting to use any of the data we'd be reading in. That
2259 * is, when the page lies beyond the EOF, or straddles the EOF
2260 * and the write will cover all of the existing data.
2261 */
2262 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2263 i_size = i_size_read(mapping->host);
2264 if (page_start >= i_size ||
2265 (offset == 0 && (pos + len) >= i_size)) {
2266 zero_user_segments(page, 0, offset,
2267 offset + len,
2268 PAGE_CACHE_SIZE);
2269 /*
2270 * PageChecked means that the parts of the page
2271 * to which we're not writing are considered up
2272 * to date. Once the data is copied to the
2273 * page, it can be set uptodate.
2274 */
2275 SetPageChecked(page);
2276 goto out;
2277 }
2278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
Nick Piggind9414772008-09-24 11:32:59 -04002280 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002281 /*
2282 * might as well read a page, it is fast enough. If we get
2283 * an error, we don't need to return it. cifs_write_end will
2284 * do a sync write instead since PG_uptodate isn't set.
2285 */
2286 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002287 } else {
2288 /* we could try using another file handle if there is one -
2289 but how would we lock it to prevent close of that handle
2290 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002291 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002292 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002293out:
2294 *pagep = page;
2295 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296}
2297
Jeff Layton3bc303c2009-09-21 06:47:50 -04002298static void
2299cifs_oplock_break(struct slow_work *work)
2300{
2301 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2302 oplock_break);
2303 struct inode *inode = cfile->pInode;
2304 struct cifsInodeInfo *cinode = CIFS_I(inode);
2305 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2306 int rc, waitrc = 0;
2307
2308 if (inode && S_ISREG(inode->i_mode)) {
2309#ifdef CONFIG_CIFS_EXPERIMENTAL
2310 if (cinode->clientCanCacheAll == 0)
Al Viro8737c932009-12-24 06:47:55 -05002311 break_lease(inode, O_RDONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002312 else if (cinode->clientCanCacheRead == 0)
Al Viro8737c932009-12-24 06:47:55 -05002313 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002314#endif
2315 rc = filemap_fdatawrite(inode->i_mapping);
2316 if (cinode->clientCanCacheRead == 0) {
2317 waitrc = filemap_fdatawait(inode->i_mapping);
2318 invalidate_remote_inode(inode);
2319 }
2320 if (!rc)
2321 rc = waitrc;
2322 if (rc)
2323 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002324 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002325 }
2326
2327 /*
2328 * releasing stale oplock after recent reconnect of smb session using
2329 * a now incorrect file handle is not a data integrity issue but do
2330 * not bother sending an oplock release if session to server still is
2331 * disconnected since oplock already released by the server
2332 */
2333 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2334 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2335 LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002336 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002337 }
2338}
2339
2340static int
2341cifs_oplock_break_get(struct slow_work *work)
2342{
2343 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2344 oplock_break);
2345 mntget(cfile->mnt);
2346 cifsFileInfo_get(cfile);
2347 return 0;
2348}
2349
2350static void
2351cifs_oplock_break_put(struct slow_work *work)
2352{
2353 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2354 oplock_break);
2355 mntput(cfile->mnt);
2356 cifsFileInfo_put(cfile);
2357}
2358
2359const struct slow_work_ops cifs_oplock_break_ops = {
2360 .get_ref = cifs_oplock_break_get,
2361 .put_ref = cifs_oplock_break_put,
2362 .execute = cifs_oplock_break,
2363};
2364
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002365const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 .readpage = cifs_readpage,
2367 .readpages = cifs_readpages,
2368 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002369 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002370 .write_begin = cifs_write_begin,
2371 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 .set_page_dirty = __set_page_dirty_nobuffers,
2373 /* .sync_page = cifs_sync_page, */
2374 /* .direct_IO = */
2375};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002376
2377/*
2378 * cifs_readpages requires the server to support a buffer large enough to
2379 * contain the header plus one complete page of data. Otherwise, we need
2380 * to leave cifs_readpages out of the address space operations.
2381 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002382const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002383 .readpage = cifs_readpage,
2384 .writepage = cifs_writepage,
2385 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002386 .write_begin = cifs_write_begin,
2387 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002388 .set_page_dirty = __set_page_dirty_nobuffers,
2389 /* .sync_page = cifs_sync_page, */
2390 /* .direct_IO = */
2391};