blob: 90f61786f516fe4645158a10c37406bed3a8eba4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
6 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/div64.h>
35#include "cifsfs.h"
36#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42
43static inline struct cifsFileInfo *cifs_init_private(
44 struct cifsFileInfo *private_data, struct inode *inode,
45 struct file *file, __u16 netfid)
46{
47 memset(private_data, 0, sizeof(struct cifsFileInfo));
48 private_data->netfid = netfid;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000049 private_data->pid = current->tgid;
Steve Frencha6ce4932009-04-09 01:14:32 +000050 mutex_init(&private_data->fh_mutex);
Roland Dreier796e5662007-05-03 04:33:45 +000051 mutex_init(&private_data->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +000052 INIT_LIST_HEAD(&private_data->llist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 private_data->pfile = file; /* needed for writepage */
Jeff Layton48541bd2009-09-12 11:54:29 -040054 private_data->pInode = igrab(inode);
Jeff Layton3bc303c2009-09-21 06:47:50 -040055 private_data->mnt = file->f_path.mnt;
Steve French4b18f2a2008-04-29 00:06:05 +000056 private_data->invalidHandle = false;
57 private_data->closePend = false;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -040058 /* Initialize reference count to one. The private data is
59 freed on the release of the last reference */
60 atomic_set(&private_data->count, 1);
Jeff Layton3bc303c2009-09-21 06:47:50 -040061 slow_work_init(&private_data->oplock_break, &cifs_oplock_break_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 return private_data;
64}
65
66static inline int cifs_convert_flags(unsigned int flags)
67{
68 if ((flags & O_ACCMODE) == O_RDONLY)
69 return GENERIC_READ;
70 else if ((flags & O_ACCMODE) == O_WRONLY)
71 return GENERIC_WRITE;
72 else if ((flags & O_ACCMODE) == O_RDWR) {
73 /* GENERIC_ALL is too much permission to request
74 can cause unnecessary access denied on create */
75 /* return GENERIC_ALL; */
76 return (GENERIC_READ | GENERIC_WRITE);
77 }
78
Jeff Laytone10f7b52008-05-14 10:21:33 -070079 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
80 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
81 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000082}
Jeff Laytone10f7b52008-05-14 10:21:33 -070083
Steve French7fc8f4e2009-02-23 20:43:11 +000084static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
85{
86 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070087
Steve French7fc8f4e2009-02-23 20:43:11 +000088 if ((flags & O_ACCMODE) == O_RDONLY)
89 posix_flags = FMODE_READ;
90 else if ((flags & O_ACCMODE) == O_WRONLY)
91 posix_flags = FMODE_WRITE;
92 else if ((flags & O_ACCMODE) == O_RDWR) {
93 /* GENERIC_ALL is too much permission to request
94 can cause unnecessary access denied on create */
95 /* return GENERIC_ALL; */
96 posix_flags = FMODE_READ | FMODE_WRITE;
97 }
98 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
99 reopening a file. They had their effect on the original open */
100 if (flags & O_APPEND)
101 posix_flags |= (fmode_t)O_APPEND;
102 if (flags & O_SYNC)
103 posix_flags |= (fmode_t)O_SYNC;
104 if (flags & O_DIRECTORY)
105 posix_flags |= (fmode_t)O_DIRECTORY;
106 if (flags & O_NOFOLLOW)
107 posix_flags |= (fmode_t)O_NOFOLLOW;
108 if (flags & O_DIRECT)
109 posix_flags |= (fmode_t)O_DIRECT;
110
111 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
114static inline int cifs_get_disposition(unsigned int flags)
115{
116 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
117 return FILE_CREATE;
118 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
119 return FILE_OVERWRITE_IF;
120 else if ((flags & O_CREAT) == O_CREAT)
121 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000122 else if ((flags & O_TRUNC) == O_TRUNC)
123 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 else
125 return FILE_OPEN;
126}
127
128/* all arguments to this function must be checked for validity in caller */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400129static inline int
130cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
131 struct cifsInodeInfo *pCifsInode,
132 struct cifsFileInfo *pCifsFile, __u32 oplock,
133 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000134{
Steve French276a74a2009-03-03 18:00:34 +0000135
Steve French276a74a2009-03-03 18:00:34 +0000136 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000137
138 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
139 if (pCifsInode == NULL) {
140 write_unlock(&GlobalSMBSeslock);
141 return -EINVAL;
142 }
143
Steve French276a74a2009-03-03 18:00:34 +0000144 if (pCifsInode->clientCanCacheRead) {
145 /* we have the inode open somewhere else
146 no need to discard cache data */
147 goto psx_client_can_cache;
148 }
149
150 /* BB FIXME need to fix this check to move it earlier into posix_open
151 BB fIX following section BB FIXME */
152
153 /* if not oplocked, invalidate inode pages if mtime or file
154 size changed */
155/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
156 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
157 (file->f_path.dentry->d_inode->i_size ==
158 (loff_t)le64_to_cpu(buf->EndOfFile))) {
159 cFYI(1, ("inode unchanged on server"));
160 } else {
161 if (file->f_path.dentry->d_inode->i_mapping) {
162 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
163 if (rc != 0)
164 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
165 }
166 cFYI(1, ("invalidating remote inode since open detected it "
167 "changed"));
168 invalidate_remote_inode(file->f_path.dentry->d_inode);
169 } */
170
171psx_client_can_cache:
172 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
173 pCifsInode->clientCanCacheAll = true;
174 pCifsInode->clientCanCacheRead = true;
175 cFYI(1, ("Exclusive Oplock granted on inode %p",
176 file->f_path.dentry->d_inode));
177 } else if ((oplock & 0xF) == OPLOCK_READ)
178 pCifsInode->clientCanCacheRead = true;
179
180 /* will have to change the unlock if we reenable the
181 filemap_fdatawrite (which does not seem necessary */
182 write_unlock(&GlobalSMBSeslock);
183 return 0;
184}
185
Steve French703a3b82009-05-21 22:21:53 +0000186static struct cifsFileInfo *
187cifs_fill_filedata(struct file *file)
188{
189 struct list_head *tmp;
190 struct cifsFileInfo *pCifsFile = NULL;
191 struct cifsInodeInfo *pCifsInode = NULL;
192
193 /* search inode for this file and fill in file->private_data */
194 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
195 read_lock(&GlobalSMBSeslock);
196 list_for_each(tmp, &pCifsInode->openFileList) {
197 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
198 if ((pCifsFile->pfile == NULL) &&
199 (pCifsFile->pid == current->tgid)) {
200 /* mode set in cifs_create */
201
202 /* needed for writepage */
203 pCifsFile->pfile = file;
204 file->private_data = pCifsFile;
205 break;
206 }
207 }
208 read_unlock(&GlobalSMBSeslock);
209
210 if (file->private_data != NULL) {
211 return pCifsFile;
212 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
213 cERROR(1, ("could not find file instance for "
214 "new file %p", file));
215 return NULL;
216}
217
Steve French276a74a2009-03-03 18:00:34 +0000218/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
220 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
221 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
222 char *full_path, int xid)
223{
224 struct timespec temp;
225 int rc;
226
227 /* want handles we can use to read with first
228 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400229 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000231 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 &pCifsInode->openFileList);
233 } else {
234 list_add(&pCifsFile->flist,
235 &pCifsInode->openFileList);
236 }
237 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if (pCifsInode->clientCanCacheRead) {
239 /* we have the inode open somewhere else
240 no need to discard cache data */
241 goto client_can_cache;
242 }
243
244 /* BB need same check in cifs_create too? */
245 /* if not oplocked, invalidate inode pages if mtime or file
246 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400247 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800248 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
249 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 (loff_t)le64_to_cpu(buf->EndOfFile))) {
251 cFYI(1, ("inode unchanged on server"));
252 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800253 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* BB no need to lock inode until after invalidate
255 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000256 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
257 if (rc != 0)
258 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 }
260 cFYI(1, ("invalidating remote inode since open detected it "
261 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800262 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 }
264
265client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000266 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800267 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 full_path, inode->i_sb, xid);
269 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800270 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000271 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000274 pCifsInode->clientCanCacheAll = true;
275 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800277 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000279 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 return rc;
282}
283
284int cifs_open(struct inode *inode, struct file *file)
285{
286 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400287 int xid;
288 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000290 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 struct cifsFileInfo *pCifsFile;
292 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 char *full_path = NULL;
294 int desiredAccess;
295 int disposition;
296 __u16 netfid;
297 FILE_ALL_INFO *buf = NULL;
298
299 xid = GetXid();
300
301 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000302 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Steve Frencha6ce4932009-04-09 01:14:32 +0000304 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000305 pCifsFile = cifs_fill_filedata(file);
306 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530307 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000308 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530309 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800312 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530314 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530316 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 }
318
Steve French7521a3c2007-07-11 18:30:34 +0000319 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000321
322 if (oplockEnabled)
323 oplock = REQ_OPLOCK;
324 else
325 oplock = 0;
326
Steve French64cc2c62009-03-04 19:54:08 +0000327 if (!tcon->broken_posix_open && tcon->unix_ext &&
328 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000329 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
330 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
331 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
332 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400333 rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
Steve French276a74a2009-03-03 18:00:34 +0000334 cifs_sb->mnt_file_mode /* ignored */,
335 oflags, &oplock, &netfid, xid);
336 if (rc == 0) {
337 cFYI(1, ("posix open succeeded"));
338 /* no need for special case handling of setting mode
339 on read only files needed here */
340
Steve French703a3b82009-05-21 22:21:53 +0000341 pCifsFile = cifs_fill_filedata(file);
Steve French276a74a2009-03-03 18:00:34 +0000342 cifs_posix_open_inode_helper(inode, file, pCifsInode,
343 pCifsFile, oplock, netfid);
344 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000345 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
346 if (tcon->ses->serverNOS)
347 cERROR(1, ("server %s of type %s returned"
348 " unexpected error on SMB posix open"
349 ", disabling posix open support."
350 " Check if server update available.",
351 tcon->ses->serverName,
352 tcon->ses->serverNOS));
353 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000354 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
355 (rc != -EOPNOTSUPP)) /* path not found or net err */
356 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000357 /* else fallthrough to retry open the old way on network i/o
358 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000359 }
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 desiredAccess = cifs_convert_flags(file->f_flags);
362
363/*********************************************************************
364 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000365 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 * O_CREAT FILE_OPEN_IF
369 * O_CREAT | O_EXCL FILE_CREATE
370 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
371 * O_TRUNC FILE_OVERWRITE
372 * none of the above FILE_OPEN
373 *
374 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000375 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 * O_CREAT | O_TRUNC is similar but truncates the existing
377 * file rather than creating a new file as FILE_SUPERSEDE does
378 * (which uses the attributes / metadata passed in on open call)
379 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000380 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 *? and the read write flags match reasonably. O_LARGEFILE
382 *? is irrelevant because largefile support is always used
383 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
384 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
385 *********************************************************************/
386
387 disposition = cifs_get_disposition(file->f_flags);
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /* BB pass O_SYNC flag through on file attributes .. BB */
390
391 /* Also refresh inode by passing in file_info buf returned by SMBOpen
392 and calling get_inode_info with returned buf (at least helps
393 non-Unix server case) */
394
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000395 /* BB we can not do this if this is the second open of a file
396 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
398 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
399 if (!buf) {
400 rc = -ENOMEM;
401 goto out;
402 }
Steve French5bafd762006-06-07 00:18:43 +0000403
404 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000405 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000406 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700407 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
408 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000409 else
410 rc = -EIO; /* no NT SMB support fall into legacy open below */
411
Steve Frencha9d02ad2005-08-24 23:06:05 -0700412 if (rc == -EIO) {
413 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000414 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700415 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
416 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
417 & CIFS_MOUNT_MAP_SPECIAL_CHR);
418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000420 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 goto out;
422 }
423 file->private_data =
424 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
425 if (file->private_data == NULL) {
426 rc = -ENOMEM;
427 goto out;
428 }
429 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000431 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800433 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 if (pCifsInode) {
435 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000436 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 &oplock, buf, full_path, xid);
438 } else {
439 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
441
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000442 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 /* time to set mode which we can not set earlier due to
444 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000445 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400446 struct cifs_unix_set_info_args args = {
447 .mode = inode->i_mode,
448 .uid = NO_CHANGE_64,
449 .gid = NO_CHANGE_64,
450 .ctime = NO_CHANGE_64,
451 .atime = NO_CHANGE_64,
452 .mtime = NO_CHANGE_64,
453 .device = 0,
454 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400455 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
456 cifs_sb->local_nls,
457 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700458 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
460 }
461
462out:
463 kfree(buf);
464 kfree(full_path);
465 FreeXid(xid);
466 return rc;
467}
468
Adrian Bunk04187262006-06-30 18:23:04 +0200469/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470/* to server was lost */
471static int cifs_relock_file(struct cifsFileInfo *cifsFile)
472{
473 int rc = 0;
474
475/* BB list all locks open on this file and relock */
476
477 return rc;
478}
479
Steve French4b18f2a2008-04-29 00:06:05 +0000480static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400483 int xid;
484 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000486 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 struct cifsFileInfo *pCifsFile;
488 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000489 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 char *full_path = NULL;
491 int desiredAccess;
492 int disposition = FILE_OPEN;
493 __u16 netfid;
494
Steve Frenchad7a2922008-02-07 23:25:02 +0000495 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000497 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return -EBADF;
499
500 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400501 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000502 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400503 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530504 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530506 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
508
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800509 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000510 cERROR(1, ("no valid name if dentry freed"));
511 dump_stack();
512 rc = -EBADF;
513 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
Steve French3a9f4622007-04-04 17:10:24 +0000515
516 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000517 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000518 cERROR(1, ("inode not valid"));
519 dump_stack();
520 rc = -EBADF;
521 goto reopen_error_exit;
522 }
Steve French50c2f752007-07-13 00:33:32 +0000523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000525 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527/* can not grab rename sem here because various ops, including
528 those that already have the rename sem can end up causing writepage
529 to get called and if the server was down that means we end up here,
530 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800531 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000533 rc = -ENOMEM;
534reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400535 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000537 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
539
Steve French3a9f4622007-04-04 17:10:24 +0000540 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 if (oplockEnabled)
544 oplock = REQ_OPLOCK;
545 else
Steve French4b18f2a2008-04-29 00:06:05 +0000546 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Steve French7fc8f4e2009-02-23 20:43:11 +0000548 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
549 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
550 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
551 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
552 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400553 rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
Steve French7fc8f4e2009-02-23 20:43:11 +0000554 cifs_sb->mnt_file_mode /* ignored */,
555 oflags, &oplock, &netfid, xid);
556 if (rc == 0) {
557 cFYI(1, ("posix reopen succeeded"));
558 goto reopen_success;
559 }
560 /* fallthrough to retry open the old way on errors, especially
561 in the reconnect path it is important to retry hard */
562 }
563
564 desiredAccess = cifs_convert_flags(file->f_flags);
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000567 by SMBOpen and then calling get_inode_info with returned buf
568 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 and server version of file size can be stale. If we knew for sure
570 that inode was not dirty locally we could do this */
571
Steve French7fc8f4e2009-02-23 20:43:11 +0000572 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700575 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400577 mutex_unlock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000578 cFYI(1, ("cifs_open returned 0x%x", rc));
579 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000581reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000583 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400584 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 pCifsInode = CIFS_I(inode);
586 if (pCifsInode) {
587 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000588 rc = filemap_write_and_wait(inode->i_mapping);
589 if (rc != 0)
590 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 /* temporarily disable caching while we
592 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000593 pCifsInode->clientCanCacheAll = false;
594 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000595 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 rc = cifs_get_inode_info_unix(&inode,
597 full_path, inode->i_sb, xid);
598 else
599 rc = cifs_get_inode_info(&inode,
600 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000601 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 } /* else we are writing out data to server already
603 and could deadlock if we tried to flush data, and
604 since we do not know if we have data that would
605 invalidate the current end of file on the server
606 we can not go to the server to get the new inod
607 info */
608 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000609 pCifsInode->clientCanCacheAll = true;
610 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800612 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000614 pCifsInode->clientCanCacheRead = true;
615 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000617 pCifsInode->clientCanCacheRead = false;
618 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
620 cifs_relock_file(pCifsFile);
621 }
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 kfree(full_path);
624 FreeXid(xid);
625 return rc;
626}
627
628int cifs_close(struct inode *inode, struct file *file)
629{
630 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000631 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 struct cifs_sb_info *cifs_sb;
633 struct cifsTconInfo *pTcon;
634 struct cifsFileInfo *pSMBFile =
635 (struct cifsFileInfo *)file->private_data;
636
637 xid = GetXid();
638
639 cifs_sb = CIFS_SB(inode->i_sb);
640 pTcon = cifs_sb->tcon;
641 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000642 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000643 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000644 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (pTcon) {
646 /* no sense reconnecting to close a file that is
647 already closed */
Steve French3b795212008-11-13 19:45:32 +0000648 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000649 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000650 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400651 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000652 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700653 /* Give write a better chance to get to
654 server ahead of the close. We do not
655 want to add a wait_q here as it would
656 increase the memory utilization as
657 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000658 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700659 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000660 cFYI(DBG2,
661 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700662 msleep(timeout);
663 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000664 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000665 if (!pTcon->need_reconnect &&
666 !pSMBFile->invalidHandle)
667 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000669 } else
670 write_unlock(&GlobalSMBSeslock);
671 } else
672 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000673
674 /* Delete any outstanding lock records.
675 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000676 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000677 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
678 list_del(&li->llist);
679 kfree(li);
680 }
Roland Dreier796e5662007-05-03 04:33:45 +0000681 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000682
Steve Frenchcbe04762005-04-28 22:41:05 -0700683 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 list_del(&pSMBFile->flist);
685 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700686 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400687 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 file->private_data = NULL;
689 } else
690 rc = -EBADF;
691
Steve French4efa53f2007-09-11 05:50:53 +0000692 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 if (list_empty(&(CIFS_I(inode)->openFileList))) {
694 cFYI(1, ("closing last open instance for inode %p", inode));
695 /* if the file is not open we do not know if we can cache info
696 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000697 CIFS_I(inode)->clientCanCacheRead = false;
698 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
Steve French4efa53f2007-09-11 05:50:53 +0000700 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000701 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 rc = CIFS_I(inode)->write_behind_rc;
703 FreeXid(xid);
704 return rc;
705}
706
707int cifs_closedir(struct inode *inode, struct file *file)
708{
709 int rc = 0;
710 int xid;
711 struct cifsFileInfo *pCFileStruct =
712 (struct cifsFileInfo *)file->private_data;
713 char *ptmp;
714
Steve French26a21b92006-05-31 18:05:34 +0000715 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 xid = GetXid();
718
719 if (pCFileStruct) {
720 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000721 struct cifs_sb_info *cifs_sb =
722 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 pTcon = cifs_sb->tcon;
725
726 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000727 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000728 if (!pCFileStruct->srch_inf.endOfSearch &&
729 !pCFileStruct->invalidHandle) {
730 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000731 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
733 cFYI(1, ("Closing uncompleted readdir with rc %d",
734 rc));
735 /* not much we can do if it fails anyway, ignore rc */
736 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000737 } else
738 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
740 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800741 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000743 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000744 cifs_small_buf_release(ptmp);
745 else
746 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 kfree(file->private_data);
749 file->private_data = NULL;
750 }
751 /* BB can we lock the filestruct while this is going on? */
752 FreeXid(xid);
753 return rc;
754}
755
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000756static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
757 __u64 offset, __u8 lockType)
758{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000759 struct cifsLockInfo *li =
760 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000761 if (li == NULL)
762 return -ENOMEM;
763 li->offset = offset;
764 li->length = len;
765 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000766 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000767 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000768 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000769 return 0;
770}
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
773{
774 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 __u32 numLock = 0;
776 __u32 numUnlock = 0;
777 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000778 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000780 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000781 __u16 netfid;
782 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000783 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 length = 1 + pfLock->fl_end - pfLock->fl_start;
786 rc = -EACCES;
787 xid = GetXid();
788
789 cFYI(1, ("Lock parm: 0x%x flockflags: "
790 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000791 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
792 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000795 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000797 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000799 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000800 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
802 if (pfLock->fl_flags & FL_ACCESS)
803 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000804 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (pfLock->fl_flags & FL_LEASE)
806 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000807 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
809 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
810
811 if (pfLock->fl_type == F_WRLCK) {
812 cFYI(1, ("F_WRLCK "));
813 numLock = 1;
814 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000815 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000817 /* Check if unlock includes more than
818 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000820 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 lockType |= LOCKING_ANDX_SHARED_LOCK;
822 numLock = 1;
823 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000824 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 numLock = 1;
826 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000827 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 lockType |= LOCKING_ANDX_SHARED_LOCK;
829 numLock = 1;
830 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000831 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800833 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000834 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530837 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530839 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
Steve French08547b02006-02-28 22:39:25 +0000841 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Steve French13a6e422008-12-02 17:24:33 +0000843 if ((tcon->ses->capabilities & CAP_UNIX) &&
844 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000845 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000846 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000847 /* BB add code here to normalize offset and length to
848 account for negative length which we can not accept over the
849 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000851 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000852 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000853 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000854 posix_lock_type = CIFS_RDLCK;
855 else
856 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000857 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000858 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000859 posix_lock_type, wait_flag);
860 FreeXid(xid);
861 return rc;
862 }
863
864 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000865 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000866 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000868 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 pfLock->fl_start, 1 /* numUnlock */ ,
870 0 /* numLock */ , lockType,
871 0 /* wait flag */ );
872 pfLock->fl_type = F_UNLCK;
873 if (rc != 0)
874 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000875 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 rc = 0;
877
878 } else {
879 /* if rc == ERR_SHARING_VIOLATION ? */
880 rc = 0; /* do not change lock type to unlock
881 since range in use */
882 }
883
884 FreeXid(xid);
885 return rc;
886 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000887
888 if (!numLock && !numUnlock) {
889 /* if no lock or unlock then nothing
890 to do since we do not know what it is */
891 FreeXid(xid);
892 return -EOPNOTSUPP;
893 }
894
895 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000896 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000897 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000898 posix_lock_type = CIFS_RDLCK;
899 else
900 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000901
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000903 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904
Steve French13a6e422008-12-02 17:24:33 +0000905 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000906 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000907 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000908 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000909 struct cifsFileInfo *fid =
910 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000911
912 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000913 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000914 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 0, numLock, lockType, wait_flag);
916
917 if (rc == 0) {
918 /* For Windows locks we must store them. */
919 rc = store_file_lock(fid, length,
920 pfLock->fl_start, lockType);
921 }
922 } else if (numUnlock) {
923 /* For each stored lock that this unlock overlaps
924 completely, unlock it. */
925 int stored_rc = 0;
926 struct cifsLockInfo *li, *tmp;
927
Steve French6b70c952006-09-21 07:35:29 +0000928 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000929 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000930 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
931 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000932 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000933 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000934 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000935 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000936 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000937 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000938 if (stored_rc)
939 rc = stored_rc;
940
941 list_del(&li->llist);
942 kfree(li);
943 }
944 }
Roland Dreier796e5662007-05-03 04:33:45 +0000945 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000946 }
947 }
948
Steve Frenchd634cc12005-08-26 14:42:59 -0500949 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 posix_lock_file_wait(file, pfLock);
951 FreeXid(xid);
952 return rc;
953}
954
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400955/*
956 * Set the timeout on write requests past EOF. For some servers (Windows)
957 * these calls can be very long.
958 *
959 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
960 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
961 * The 10M cutoff is totally arbitrary. A better scheme for this would be
962 * welcome if someone wants to suggest one.
963 *
964 * We may be able to do a better job with this if there were some way to
965 * declare that a file should be sparse.
966 */
967static int
968cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
969{
970 if (offset <= cifsi->server_eof)
971 return CIFS_STD_OP;
972 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
973 return CIFS_VLONG_OP;
974 else
975 return CIFS_LONG_OP;
976}
977
978/* update the file size (if needed) after a write */
979static void
980cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
981 unsigned int bytes_written)
982{
983 loff_t end_of_write = offset + bytes_written;
984
985 if (end_of_write > cifsi->server_eof)
986 cifsi->server_eof = end_of_write;
987}
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989ssize_t cifs_user_write(struct file *file, const char __user *write_data,
990 size_t write_size, loff_t *poffset)
991{
992 int rc = 0;
993 unsigned int bytes_written = 0;
994 unsigned int total_written;
995 struct cifs_sb_info *cifs_sb;
996 struct cifsTconInfo *pTcon;
997 int xid, long_op;
998 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400999 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001001 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 pTcon = cifs_sb->tcon;
1004
1005 /* cFYI(1,
1006 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001007 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 if (file->private_data == NULL)
1010 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001011 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001012
Jeff Layton838726c2008-08-28 07:54:59 -04001013 rc = generic_write_checks(file, poffset, &write_size, 0);
1014 if (rc)
1015 return rc;
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001019 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 for (total_written = 0; write_size > total_written;
1021 total_written += bytes_written) {
1022 rc = -EAGAIN;
1023 while (rc == -EAGAIN) {
1024 if (file->private_data == NULL) {
1025 /* file has been closed on us */
1026 FreeXid(xid);
1027 /* if we have gotten here we have written some data
1028 and blocked, and the file has been freed on us while
1029 we blocked so return what we managed to write */
1030 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (open_file->closePend) {
1033 FreeXid(xid);
1034 if (total_written)
1035 return total_written;
1036 else
1037 return -EBADF;
1038 }
1039 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 /* we could deadlock if we called
1041 filemap_fdatawait from here so tell
1042 reopen_file not to flush data to server
1043 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001044 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (rc != 0)
1046 break;
1047 }
1048
1049 rc = CIFSSMBWrite(xid, pTcon,
1050 open_file->netfid,
1051 min_t(const int, cifs_sb->wsize,
1052 write_size - total_written),
1053 *poffset, &bytes_written,
1054 NULL, write_data + total_written, long_op);
1055 }
1056 if (rc || (bytes_written == 0)) {
1057 if (total_written)
1058 break;
1059 else {
1060 FreeXid(xid);
1061 return rc;
1062 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001063 } else {
1064 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001066 }
Steve French133672e2007-11-13 22:41:37 +00001067 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 15 seconds is plenty */
1069 }
1070
Steve Frencha4544342005-08-24 13:59:35 -07001071 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001074 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1075 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001076/* Do not update local mtime - server will set its actual value on write
1077 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001078 * current_fs_time(inode->i_sb);*/
1079 if (total_written > 0) {
1080 spin_lock(&inode->i_lock);
1081 if (*poffset > file->f_path.dentry->d_inode->i_size)
1082 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001084 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001086 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088 FreeXid(xid);
1089 return total_written;
1090}
1091
1092static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001093 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
1095 int rc = 0;
1096 unsigned int bytes_written = 0;
1097 unsigned int total_written;
1098 struct cifs_sb_info *cifs_sb;
1099 struct cifsTconInfo *pTcon;
1100 int xid, long_op;
1101 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001102 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001104 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 pTcon = cifs_sb->tcon;
1107
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001108 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001109 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 if (file->private_data == NULL)
1112 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001113 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001117 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 for (total_written = 0; write_size > total_written;
1119 total_written += bytes_written) {
1120 rc = -EAGAIN;
1121 while (rc == -EAGAIN) {
1122 if (file->private_data == NULL) {
1123 /* file has been closed on us */
1124 FreeXid(xid);
1125 /* if we have gotten here we have written some data
1126 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001127 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 write */
1129 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 if (open_file->closePend) {
1132 FreeXid(xid);
1133 if (total_written)
1134 return total_written;
1135 else
1136 return -EBADF;
1137 }
1138 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 /* we could deadlock if we called
1140 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001141 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001143 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if (rc != 0)
1145 break;
1146 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001147 if (experimEnabled || (pTcon->ses->server &&
1148 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001149 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001150 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001151 struct kvec iov[2];
1152 unsigned int len;
1153
Steve French0ae0efa2005-10-10 10:57:19 -07001154 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001155 write_size - total_written);
1156 /* iov[0] is reserved for smb header */
1157 iov[1].iov_base = (char *)write_data +
1158 total_written;
1159 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001160 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001161 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001162 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001163 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001164 } else
Steve French60808232006-04-22 15:53:05 +00001165 rc = CIFSSMBWrite(xid, pTcon,
1166 open_file->netfid,
1167 min_t(const int, cifs_sb->wsize,
1168 write_size - total_written),
1169 *poffset, &bytes_written,
1170 write_data + total_written,
1171 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173 if (rc || (bytes_written == 0)) {
1174 if (total_written)
1175 break;
1176 else {
1177 FreeXid(xid);
1178 return rc;
1179 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001180 } else {
1181 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001183 }
Steve French133672e2007-11-13 22:41:37 +00001184 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 15 seconds is plenty */
1186 }
1187
Steve Frencha4544342005-08-24 13:59:35 -07001188 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001191 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001192/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001193/* file->f_path.dentry->d_inode->i_ctime =
1194 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1195 if (total_written > 0) {
1196 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1197 if (*poffset > file->f_path.dentry->d_inode->i_size)
1198 i_size_write(file->f_path.dentry->d_inode,
1199 *poffset);
1200 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 }
Steve French3677db12007-02-26 16:46:11 +00001202 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
1204 FreeXid(xid);
1205 return total_written;
1206}
1207
Steve French630f3f0c2007-10-25 21:17:17 +00001208#ifdef CONFIG_CIFS_EXPERIMENTAL
1209struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1210{
1211 struct cifsFileInfo *open_file = NULL;
1212
1213 read_lock(&GlobalSMBSeslock);
1214 /* we could simply get the first_list_entry since write-only entries
1215 are always at the end of the list but since the first entry might
1216 have a close pending, we go through the whole list */
1217 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1218 if (open_file->closePend)
1219 continue;
1220 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1221 (open_file->pfile->f_flags & O_RDONLY))) {
1222 if (!open_file->invalidHandle) {
1223 /* found a good file */
1224 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001225 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001226 read_unlock(&GlobalSMBSeslock);
1227 return open_file;
1228 } /* else might as well continue, and look for
1229 another, or simply have the caller reopen it
1230 again rather than trying to fix this handle */
1231 } else /* write only file */
1232 break; /* write only files are last so must be done */
1233 }
1234 read_unlock(&GlobalSMBSeslock);
1235 return NULL;
1236}
1237#endif
1238
Steve Frenchdd99cd82005-10-05 19:32:49 -07001239struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001240{
1241 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001242 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001243 int rc;
Steve French6148a742005-10-05 12:23:19 -07001244
Steve French60808232006-04-22 15:53:05 +00001245 /* Having a null inode here (because mapping->host was set to zero by
1246 the VFS or MM) should not happen but we had reports of on oops (due to
1247 it being zero) during stress testcases so we need to check for it */
1248
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001249 if (cifs_inode == NULL) {
1250 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001251 dump_stack();
1252 return NULL;
1253 }
1254
Steve French6148a742005-10-05 12:23:19 -07001255 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001256refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001257 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001258 if (open_file->closePend ||
1259 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001260 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001261
Steve French6148a742005-10-05 12:23:19 -07001262 if (open_file->pfile &&
1263 ((open_file->pfile->f_flags & O_RDWR) ||
1264 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001265 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001266
1267 if (!open_file->invalidHandle) {
1268 /* found a good writable file */
1269 read_unlock(&GlobalSMBSeslock);
1270 return open_file;
1271 }
Steve French8840dee2007-11-16 23:05:52 +00001272
Steve French6148a742005-10-05 12:23:19 -07001273 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001274 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001275 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001276 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001277 if (!open_file->closePend)
1278 return open_file;
1279 else { /* start over in case this was deleted */
1280 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001281 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001282 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001283 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001284 }
1285 }
Steve French9b22b0b2007-10-02 01:11:08 +00001286
1287 /* if it fails, try another handle if possible -
1288 (we can not do this if closePending since
1289 loop could be modified - in which case we
1290 have to start at the beginning of the list
1291 again. Note that it would be bad
1292 to hold up writepages here (rather than
1293 in caller) with continuous retries */
1294 cFYI(1, ("wp failed on reopen file"));
1295 read_lock(&GlobalSMBSeslock);
1296 /* can not use this handle, no write
1297 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001298 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001299
Steve French9b22b0b2007-10-02 01:11:08 +00001300 if (open_file->closePend) /* list could have changed */
1301 goto refind_writable;
1302 /* else we simply continue to the next entry. Thus
1303 we do not loop on reopen errors. If we
1304 can not reopen the file, for example if we
1305 reconnected to a server with another client
1306 racing to delete or lock the file we would not
1307 make progress if we restarted before the beginning
1308 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001309 }
1310 }
Jeff Layton2846d382008-09-22 21:33:33 -04001311 /* couldn't find useable FH with same pid, try any available */
1312 if (!any_available) {
1313 any_available = true;
1314 goto refind_writable;
1315 }
Steve French6148a742005-10-05 12:23:19 -07001316 read_unlock(&GlobalSMBSeslock);
1317 return NULL;
1318}
1319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1321{
1322 struct address_space *mapping = page->mapping;
1323 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1324 char *write_data;
1325 int rc = -EFAULT;
1326 int bytes_written = 0;
1327 struct cifs_sb_info *cifs_sb;
1328 struct cifsTconInfo *pTcon;
1329 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001330 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332 if (!mapping || !mapping->host)
1333 return -EFAULT;
1334
1335 inode = page->mapping->host;
1336 cifs_sb = CIFS_SB(inode->i_sb);
1337 pTcon = cifs_sb->tcon;
1338
1339 offset += (loff_t)from;
1340 write_data = kmap(page);
1341 write_data += from;
1342
1343 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1344 kunmap(page);
1345 return -EIO;
1346 }
1347
1348 /* racing with truncate? */
1349 if (offset > mapping->host->i_size) {
1350 kunmap(page);
1351 return 0; /* don't care */
1352 }
1353
1354 /* check to make sure that we are not extending the file */
1355 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001356 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Steve French6148a742005-10-05 12:23:19 -07001358 open_file = find_writable_file(CIFS_I(mapping->host));
1359 if (open_file) {
1360 bytes_written = cifs_write(open_file->pfile, write_data,
1361 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001362 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001364 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001365 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001366 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001367 else if (bytes_written < 0)
1368 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001369 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 cFYI(1, ("No writeable filehandles for inode"));
1371 rc = -EIO;
1372 }
1373
1374 kunmap(page);
1375 return rc;
1376}
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001379 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
Steve French37c0eb42005-10-05 14:50:29 -07001381 struct backing_dev_info *bdi = mapping->backing_dev_info;
1382 unsigned int bytes_to_write;
1383 unsigned int bytes_written;
1384 struct cifs_sb_info *cifs_sb;
1385 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001386 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001387 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001388 int range_whole = 0;
1389 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001390 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001391 int n_iov = 0;
1392 pgoff_t next;
1393 int nr_pages;
1394 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001395 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001396 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001397 struct page *page;
1398 struct pagevec pvec;
1399 int rc = 0;
1400 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001401 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Steve French37c0eb42005-10-05 14:50:29 -07001403 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001404
Steve French37c0eb42005-10-05 14:50:29 -07001405 /*
1406 * If wsize is smaller that the page cache size, default to writing
1407 * one page at a time via cifs_writepage
1408 */
1409 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1410 return generic_writepages(mapping, wbc);
1411
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001412 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1413 if (cifs_sb->tcon->ses->server->secMode &
1414 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1415 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001416 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001417
Steve French9a0c8232007-02-02 04:21:57 +00001418 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001419 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001420 return generic_writepages(mapping, wbc);
1421
1422
Steve French37c0eb42005-10-05 14:50:29 -07001423 /*
1424 * BB: Is this meaningful for a non-block-device file system?
1425 * If it is, we should test it again after we do I/O
1426 */
1427 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1428 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001429 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001430 return 0;
1431 }
1432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 xid = GetXid();
1434
Steve French37c0eb42005-10-05 14:50:29 -07001435 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001436 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001437 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001438 end = -1;
1439 } else {
1440 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1441 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1442 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1443 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001444 scanned = 1;
1445 }
1446retry:
1447 while (!done && (index <= end) &&
1448 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1449 PAGECACHE_TAG_DIRTY,
1450 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1451 int first;
1452 unsigned int i;
1453
Steve French37c0eb42005-10-05 14:50:29 -07001454 first = -1;
1455 next = 0;
1456 n_iov = 0;
1457 bytes_to_write = 0;
1458
1459 for (i = 0; i < nr_pages; i++) {
1460 page = pvec.pages[i];
1461 /*
1462 * At this point we hold neither mapping->tree_lock nor
1463 * lock on the page itself: the page may be truncated or
1464 * invalidated (changing page->mapping to NULL), or even
1465 * swizzled back from swapper_space to tmpfs file
1466 * mapping
1467 */
1468
1469 if (first < 0)
1470 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001471 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001472 break;
1473
1474 if (unlikely(page->mapping != mapping)) {
1475 unlock_page(page);
1476 break;
1477 }
1478
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001479 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001480 done = 1;
1481 unlock_page(page);
1482 break;
1483 }
1484
1485 if (next && (page->index != next)) {
1486 /* Not next consecutive page */
1487 unlock_page(page);
1488 break;
1489 }
1490
1491 if (wbc->sync_mode != WB_SYNC_NONE)
1492 wait_on_page_writeback(page);
1493
1494 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001495 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001496 unlock_page(page);
1497 break;
1498 }
Steve French84d2f072005-10-12 15:32:05 -07001499
Linus Torvaldscb876f42006-12-23 16:19:07 -08001500 /*
1501 * This actually clears the dirty bit in the radix tree.
1502 * See cifs_writepage() for more commentary.
1503 */
1504 set_page_writeback(page);
1505
Steve French84d2f072005-10-12 15:32:05 -07001506 if (page_offset(page) >= mapping->host->i_size) {
1507 done = 1;
1508 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001509 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001510 break;
1511 }
1512
Steve French37c0eb42005-10-05 14:50:29 -07001513 /*
1514 * BB can we get rid of this? pages are held by pvec
1515 */
1516 page_cache_get(page);
1517
Steve French84d2f072005-10-12 15:32:05 -07001518 len = min(mapping->host->i_size - page_offset(page),
1519 (loff_t)PAGE_CACHE_SIZE);
1520
Steve French37c0eb42005-10-05 14:50:29 -07001521 /* reserve iov[0] for the smb header */
1522 n_iov++;
1523 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001524 iov[n_iov].iov_len = len;
1525 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001526
1527 if (first < 0) {
1528 first = i;
1529 offset = page_offset(page);
1530 }
1531 next = page->index + 1;
1532 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1533 break;
1534 }
1535 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001536 /* Search for a writable handle every time we call
1537 * CIFSSMBWrite2. We can't rely on the last handle
1538 * we used to still be valid
1539 */
1540 open_file = find_writable_file(CIFS_I(mapping->host));
1541 if (!open_file) {
1542 cERROR(1, ("No writable handles for inode"));
1543 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001544 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001545 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001546 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1547 open_file->netfid,
1548 bytes_to_write, offset,
1549 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001550 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001551 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001552 cifs_update_eof(cifsi, offset, bytes_written);
1553
Steve French23e7dd72005-10-20 13:44:56 -07001554 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001555 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001556 rc, bytes_written));
1557 /* BB what if continued retry is
1558 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001559 if (rc == -ENOSPC)
1560 set_bit(AS_ENOSPC, &mapping->flags);
1561 else
1562 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001563 } else {
1564 cifs_stats_bytes_written(cifs_sb->tcon,
1565 bytes_written);
1566 }
Steve French37c0eb42005-10-05 14:50:29 -07001567 }
1568 for (i = 0; i < n_iov; i++) {
1569 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001570 /* Should we also set page error on
1571 success rc but too little data written? */
1572 /* BB investigate retry logic on temporary
1573 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001574 when page marked as error */
1575 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001576 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001577 kunmap(page);
1578 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001579 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001580 page_cache_release(page);
1581 }
1582 if ((wbc->nr_to_write -= n_iov) <= 0)
1583 done = 1;
1584 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001585 } else
1586 /* Need to re-find the pages we skipped */
1587 index = pvec.pages[0]->index + 1;
1588
Steve French37c0eb42005-10-05 14:50:29 -07001589 pagevec_release(&pvec);
1590 }
1591 if (!scanned && !done) {
1592 /*
1593 * We hit the last page and there is more work to be done: wrap
1594 * back to the start of the file
1595 */
1596 scanned = 1;
1597 index = 0;
1598 goto retry;
1599 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001600 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001601 mapping->writeback_index = index;
1602
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001604 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return rc;
1606}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001608static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609{
1610 int rc = -EFAULT;
1611 int xid;
1612
1613 xid = GetXid();
1614/* BB add check for wbc flags */
1615 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001616 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001618
1619 /*
1620 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1621 *
1622 * A writepage() implementation always needs to do either this,
1623 * or re-dirty the page with "redirty_page_for_writepage()" in
1624 * the case of a failure.
1625 *
1626 * Just unlocking the page will cause the radix tree tag-bits
1627 * to fail to update with the state of the page correctly.
1628 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001629 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1631 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1632 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001633 end_page_writeback(page);
1634 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 FreeXid(xid);
1636 return rc;
1637}
1638
Nick Piggind9414772008-09-24 11:32:59 -04001639static int cifs_write_end(struct file *file, struct address_space *mapping,
1640 loff_t pos, unsigned len, unsigned copied,
1641 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
Nick Piggind9414772008-09-24 11:32:59 -04001643 int rc;
1644 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Nick Piggind9414772008-09-24 11:32:59 -04001646 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1647 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001648
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001649 if (PageChecked(page)) {
1650 if (copied == len)
1651 SetPageUptodate(page);
1652 ClearPageChecked(page);
1653 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001654 SetPageUptodate(page);
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001657 char *page_data;
1658 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1659 int xid;
1660
1661 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 /* this is probably better than directly calling
1663 partialpage_write since in this function the file handle is
1664 known which we might as well leverage */
1665 /* BB check if anything else missing out of ppw
1666 such as updating last write time */
1667 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001668 rc = cifs_write(file, page_data + offset, copied, &pos);
1669 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001671
1672 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001673 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001674 rc = copied;
1675 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 set_page_dirty(page);
1677 }
1678
Nick Piggind9414772008-09-24 11:32:59 -04001679 if (rc > 0) {
1680 spin_lock(&inode->i_lock);
1681 if (pos > inode->i_size)
1682 i_size_write(inode, pos);
1683 spin_unlock(&inode->i_lock);
1684 }
1685
1686 unlock_page(page);
1687 page_cache_release(page);
1688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 return rc;
1690}
1691
1692int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1693{
1694 int xid;
1695 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001696 struct cifsTconInfo *tcon;
1697 struct cifsFileInfo *smbfile =
1698 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001699 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 xid = GetXid();
1702
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001703 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001705
Jeff Laytoncea21802007-11-20 23:19:03 +00001706 rc = filemap_write_and_wait(inode->i_mapping);
1707 if (rc == 0) {
1708 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001710 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001711 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001712 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001713 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001714 }
Steve Frenchb298f222009-02-21 21:17:43 +00001715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 FreeXid(xid);
1717 return rc;
1718}
1719
NeilBrown3978d712006-03-26 01:37:17 -08001720/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721{
1722 struct address_space *mapping;
1723 struct inode *inode;
1724 unsigned long index = page->index;
1725 unsigned int rpages = 0;
1726 int rc = 0;
1727
1728 cFYI(1, ("sync page %p",page));
1729 mapping = page->mapping;
1730 if (!mapping)
1731 return 0;
1732 inode = mapping->host;
1733 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001734 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001736/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1738
Steve French26a21b92006-05-31 18:05:34 +00001739/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
NeilBrown3978d712006-03-26 01:37:17 -08001741#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 if (rc < 0)
1743 return rc;
1744 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001745#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746} */
1747
1748/*
1749 * As file closes, flush all cached write data for this inode checking
1750 * for write behind errors.
1751 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001752int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001754 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 int rc = 0;
1756
1757 /* Rather than do the steps manually:
1758 lock the inode for writing
1759 loop through pages looking for write behind data (dirty pages)
1760 coalesce into contiguous 16K (or smaller) chunks to write to server
1761 send to server (prefer in parallel)
1762 deal with writebehind errors
1763 unlock inode for writing
1764 filemapfdatawrite appears easier for the time being */
1765
1766 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001767 /* reset wb rc if we were able to write out dirty pages */
1768 if (!rc) {
1769 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001771 }
Steve French50c2f752007-07-13 00:33:32 +00001772
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001773 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
1775 return rc;
1776}
1777
1778ssize_t cifs_user_read(struct file *file, char __user *read_data,
1779 size_t read_size, loff_t *poffset)
1780{
1781 int rc = -EACCES;
1782 unsigned int bytes_read = 0;
1783 unsigned int total_read = 0;
1784 unsigned int current_read_size;
1785 struct cifs_sb_info *cifs_sb;
1786 struct cifsTconInfo *pTcon;
1787 int xid;
1788 struct cifsFileInfo *open_file;
1789 char *smb_read_data;
1790 char __user *current_offset;
1791 struct smb_com_read_rsp *pSMBr;
1792
1793 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001794 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 pTcon = cifs_sb->tcon;
1796
1797 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301798 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301800 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
1802 open_file = (struct cifsFileInfo *)file->private_data;
1803
Steve Frenchad7a2922008-02-07 23:25:02 +00001804 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 for (total_read = 0, current_offset = read_data;
1808 read_size > total_read;
1809 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 cifs_sb->rsize);
1812 rc = -EAGAIN;
1813 smb_read_data = NULL;
1814 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001815 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001818 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 if (rc != 0)
1820 break;
1821 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001822 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001823 open_file->netfid,
1824 current_read_size, *poffset,
1825 &bytes_read, &smb_read_data,
1826 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001829 if (copy_to_user(current_offset,
1830 smb_read_data +
1831 4 /* RFC1001 length field */ +
1832 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001833 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001834 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001835
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001836 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001837 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001838 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001839 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 smb_read_data = NULL;
1841 }
1842 }
1843 if (rc || (bytes_read == 0)) {
1844 if (total_read) {
1845 break;
1846 } else {
1847 FreeXid(xid);
1848 return rc;
1849 }
1850 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001851 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 *poffset += bytes_read;
1853 }
1854 }
1855 FreeXid(xid);
1856 return total_read;
1857}
1858
1859
1860static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1861 loff_t *poffset)
1862{
1863 int rc = -EACCES;
1864 unsigned int bytes_read = 0;
1865 unsigned int total_read;
1866 unsigned int current_read_size;
1867 struct cifs_sb_info *cifs_sb;
1868 struct cifsTconInfo *pTcon;
1869 int xid;
1870 char *current_offset;
1871 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001872 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001875 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 pTcon = cifs_sb->tcon;
1877
1878 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301879 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301881 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 }
1883 open_file = (struct cifsFileInfo *)file->private_data;
1884
1885 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1886 cFYI(1, ("attempting read on write only file instance"));
1887
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001888 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 read_size > total_read;
1890 total_read += bytes_read, current_offset += bytes_read) {
1891 current_read_size = min_t(const int, read_size - total_read,
1892 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001893 /* For windows me and 9x we do not want to request more
1894 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001895 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001896 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1897 current_read_size = min_t(const int, current_read_size,
1898 pTcon->ses->server->maxBuf - 128);
1899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 rc = -EAGAIN;
1901 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001904 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 if (rc != 0)
1906 break;
1907 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001908 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001909 open_file->netfid,
1910 current_read_size, *poffset,
1911 &bytes_read, &current_offset,
1912 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 }
1914 if (rc || (bytes_read == 0)) {
1915 if (total_read) {
1916 break;
1917 } else {
1918 FreeXid(xid);
1919 return rc;
1920 }
1921 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001922 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 *poffset += bytes_read;
1924 }
1925 }
1926 FreeXid(xid);
1927 return total_read;
1928}
1929
1930int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1931{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001932 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 int rc, xid;
1934
1935 xid = GetXid();
1936 rc = cifs_revalidate(dentry);
1937 if (rc) {
1938 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1939 FreeXid(xid);
1940 return rc;
1941 }
1942 rc = generic_file_mmap(file, vma);
1943 FreeXid(xid);
1944 return rc;
1945}
1946
1947
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001948static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 struct list_head *pages, int bytes_read, char *data,
1950 struct pagevec *plru_pvec)
1951{
1952 struct page *page;
1953 char *target;
1954
1955 while (bytes_read > 0) {
1956 if (list_empty(pages))
1957 break;
1958
1959 page = list_entry(pages->prev, struct page, lru);
1960 list_del(&page->lru);
1961
1962 if (add_to_page_cache(page, mapping, page->index,
1963 GFP_KERNEL)) {
1964 page_cache_release(page);
1965 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001966 data += PAGE_CACHE_SIZE;
1967 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 continue;
1969 }
1970
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001971 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
1973 if (PAGE_CACHE_SIZE > bytes_read) {
1974 memcpy(target, data, bytes_read);
1975 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 PAGE_CACHE_SIZE - bytes_read);
1978 bytes_read = 0;
1979 } else {
1980 memcpy(target, data, PAGE_CACHE_SIZE);
1981 bytes_read -= PAGE_CACHE_SIZE;
1982 }
1983 kunmap_atomic(target, KM_USER0);
1984
1985 flush_dcache_page(page);
1986 SetPageUptodate(page);
1987 unlock_page(page);
1988 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001989 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 data += PAGE_CACHE_SIZE;
1991 }
1992 return;
1993}
1994
1995static int cifs_readpages(struct file *file, struct address_space *mapping,
1996 struct list_head *page_list, unsigned num_pages)
1997{
1998 int rc = -EACCES;
1999 int xid;
2000 loff_t offset;
2001 struct page *page;
2002 struct cifs_sb_info *cifs_sb;
2003 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00002004 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002005 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 char *smb_read_data = NULL;
2007 struct smb_com_read_rsp *pSMBr;
2008 struct pagevec lru_pvec;
2009 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002010 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
2012 xid = GetXid();
2013 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302014 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302016 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
2018 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002019 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002021
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00002023 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 for (i = 0; i < num_pages; ) {
2025 unsigned contig_pages;
2026 struct page *tmp_page;
2027 unsigned long expected_index;
2028
2029 if (list_empty(page_list))
2030 break;
2031
2032 page = list_entry(page_list->prev, struct page, lru);
2033 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2034
2035 /* count adjacent pages that we will read into */
2036 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002039 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if (tmp_page->index == expected_index) {
2041 contig_pages++;
2042 expected_index++;
2043 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002044 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 }
2046 if (contig_pages + i > num_pages)
2047 contig_pages = num_pages - i;
2048
2049 /* for reads over a certain size could initiate async
2050 read ahead */
2051
2052 read_size = contig_pages * PAGE_CACHE_SIZE;
2053 /* Read size needs to be in multiples of one page */
2054 read_size = min_t(const unsigned int, read_size,
2055 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002056 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002057 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 rc = -EAGAIN;
2059 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002060 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002062 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 if (rc != 0)
2064 break;
2065 }
2066
Steve Frenchbfa0d752005-08-31 21:50:37 -07002067 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002068 open_file->netfid,
2069 read_size, offset,
2070 &bytes_read, &smb_read_data,
2071 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002072 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002073 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002075 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002076 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002077 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002078 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 smb_read_data = NULL;
2080 }
2081 }
2082 }
2083 if ((rc < 0) || (smb_read_data == NULL)) {
2084 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 break;
2086 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002087 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2089 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2090 smb_read_data + 4 /* RFC1001 hdr */ +
2091 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2092
2093 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002094 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002095 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 i++; /* account for partial page */
2097
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002098 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002100 /* BB do we need to verify this common case ?
2101 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 we will hit it on next read */
2103
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002104 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 }
2106 } else {
2107 cFYI(1, ("No bytes read (%d) at offset %lld . "
2108 "Cleaning remaining pages from readahead list",
2109 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 break;
2113 }
2114 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002115 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002116 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002117 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002118 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 smb_read_data = NULL;
2120 }
2121 bytes_read = 0;
2122 }
2123
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002124 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126/* need to free smb_read_data buf before exit */
2127 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002129 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002130 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002131 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
2135 FreeXid(xid);
2136 return rc;
2137}
2138
2139static int cifs_readpage_worker(struct file *file, struct page *page,
2140 loff_t *poffset)
2141{
2142 char *read_data;
2143 int rc;
2144
2145 page_cache_get(page);
2146 read_data = kmap(page);
2147 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (rc < 0)
2152 goto io_error;
2153 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002154 cFYI(1, ("Bytes read %d", rc));
2155
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002156 file->f_path.dentry->d_inode->i_atime =
2157 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 if (PAGE_CACHE_SIZE > rc)
2160 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2161
2162 flush_dcache_page(page);
2163 SetPageUptodate(page);
2164 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002167 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 page_cache_release(page);
2169 return rc;
2170}
2171
2172static int cifs_readpage(struct file *file, struct page *page)
2173{
2174 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2175 int rc = -EACCES;
2176 int xid;
2177
2178 xid = GetXid();
2179
2180 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302181 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302183 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002186 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 page, (int)offset, (int)offset));
2188
2189 rc = cifs_readpage_worker(file, page, &offset);
2190
2191 unlock_page(page);
2192
2193 FreeXid(xid);
2194 return rc;
2195}
2196
Steve Frencha403a0a2007-07-26 15:54:16 +00002197static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2198{
2199 struct cifsFileInfo *open_file;
2200
2201 read_lock(&GlobalSMBSeslock);
2202 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2203 if (open_file->closePend)
2204 continue;
2205 if (open_file->pfile &&
2206 ((open_file->pfile->f_flags & O_RDWR) ||
2207 (open_file->pfile->f_flags & O_WRONLY))) {
2208 read_unlock(&GlobalSMBSeslock);
2209 return 1;
2210 }
2211 }
2212 read_unlock(&GlobalSMBSeslock);
2213 return 0;
2214}
2215
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216/* We do not want to update the file size from server for inodes
2217 open for write - to avoid races with writepage extending
2218 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002219 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 but this is tricky to do without racing with writebehind
2221 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002222bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223{
Steve Frencha403a0a2007-07-26 15:54:16 +00002224 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002225 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002226
Steve Frencha403a0a2007-07-26 15:54:16 +00002227 if (is_inode_writable(cifsInode)) {
2228 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002229 struct cifs_sb_info *cifs_sb;
2230
Steve Frenchc32a0b62006-01-12 14:41:28 -08002231 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002232 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002233 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002234 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002235 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002236 }
2237
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002238 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002239 return true;
Steve French7ba526312007-02-08 18:14:13 +00002240
Steve French4b18f2a2008-04-29 00:06:05 +00002241 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002242 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002243 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244}
2245
Nick Piggind9414772008-09-24 11:32:59 -04002246static int cifs_write_begin(struct file *file, struct address_space *mapping,
2247 loff_t pos, unsigned len, unsigned flags,
2248 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249{
Nick Piggind9414772008-09-24 11:32:59 -04002250 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2251 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002252 loff_t page_start = pos & PAGE_MASK;
2253 loff_t i_size;
2254 struct page *page;
2255 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Nick Piggind9414772008-09-24 11:32:59 -04002257 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2258
Nick Piggin54566b22009-01-04 12:00:53 -08002259 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002260 if (!page) {
2261 rc = -ENOMEM;
2262 goto out;
2263 }
Nick Piggind9414772008-09-24 11:32:59 -04002264
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002265 if (PageUptodate(page))
2266 goto out;
Steve French8a236262007-03-06 00:31:00 +00002267
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002268 /*
2269 * If we write a full page it will be up to date, no need to read from
2270 * the server. If the write is short, we'll end up doing a sync write
2271 * instead.
2272 */
2273 if (len == PAGE_CACHE_SIZE)
2274 goto out;
2275
2276 /*
2277 * optimize away the read when we have an oplock, and we're not
2278 * expecting to use any of the data we'd be reading in. That
2279 * is, when the page lies beyond the EOF, or straddles the EOF
2280 * and the write will cover all of the existing data.
2281 */
2282 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2283 i_size = i_size_read(mapping->host);
2284 if (page_start >= i_size ||
2285 (offset == 0 && (pos + len) >= i_size)) {
2286 zero_user_segments(page, 0, offset,
2287 offset + len,
2288 PAGE_CACHE_SIZE);
2289 /*
2290 * PageChecked means that the parts of the page
2291 * to which we're not writing are considered up
2292 * to date. Once the data is copied to the
2293 * page, it can be set uptodate.
2294 */
2295 SetPageChecked(page);
2296 goto out;
2297 }
2298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Nick Piggind9414772008-09-24 11:32:59 -04002300 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002301 /*
2302 * might as well read a page, it is fast enough. If we get
2303 * an error, we don't need to return it. cifs_write_end will
2304 * do a sync write instead since PG_uptodate isn't set.
2305 */
2306 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002307 } else {
2308 /* we could try using another file handle if there is one -
2309 but how would we lock it to prevent close of that handle
2310 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002311 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002312 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002313out:
2314 *pagep = page;
2315 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316}
2317
Jeff Layton3bc303c2009-09-21 06:47:50 -04002318static void
2319cifs_oplock_break(struct slow_work *work)
2320{
2321 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2322 oplock_break);
2323 struct inode *inode = cfile->pInode;
2324 struct cifsInodeInfo *cinode = CIFS_I(inode);
2325 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2326 int rc, waitrc = 0;
2327
2328 if (inode && S_ISREG(inode->i_mode)) {
2329#ifdef CONFIG_CIFS_EXPERIMENTAL
2330 if (cinode->clientCanCacheAll == 0)
2331 break_lease(inode, FMODE_READ);
2332 else if (cinode->clientCanCacheRead == 0)
2333 break_lease(inode, FMODE_WRITE);
2334#endif
2335 rc = filemap_fdatawrite(inode->i_mapping);
2336 if (cinode->clientCanCacheRead == 0) {
2337 waitrc = filemap_fdatawait(inode->i_mapping);
2338 invalidate_remote_inode(inode);
2339 }
2340 if (!rc)
2341 rc = waitrc;
2342 if (rc)
2343 cinode->write_behind_rc = rc;
2344 cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
2345 }
2346
2347 /*
2348 * releasing stale oplock after recent reconnect of smb session using
2349 * a now incorrect file handle is not a data integrity issue but do
2350 * not bother sending an oplock release if session to server still is
2351 * disconnected since oplock already released by the server
2352 */
2353 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2354 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2355 LOCKING_ANDX_OPLOCK_RELEASE, false);
2356 cFYI(1, ("Oplock release rc = %d", rc));
2357 }
2358}
2359
2360static int
2361cifs_oplock_break_get(struct slow_work *work)
2362{
2363 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2364 oplock_break);
2365 mntget(cfile->mnt);
2366 cifsFileInfo_get(cfile);
2367 return 0;
2368}
2369
2370static void
2371cifs_oplock_break_put(struct slow_work *work)
2372{
2373 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2374 oplock_break);
2375 mntput(cfile->mnt);
2376 cifsFileInfo_put(cfile);
2377}
2378
2379const struct slow_work_ops cifs_oplock_break_ops = {
2380 .get_ref = cifs_oplock_break_get,
2381 .put_ref = cifs_oplock_break_put,
2382 .execute = cifs_oplock_break,
2383};
2384
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002385const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 .readpage = cifs_readpage,
2387 .readpages = cifs_readpages,
2388 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002389 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002390 .write_begin = cifs_write_begin,
2391 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 .set_page_dirty = __set_page_dirty_nobuffers,
2393 /* .sync_page = cifs_sync_page, */
2394 /* .direct_IO = */
2395};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002396
2397/*
2398 * cifs_readpages requires the server to support a buffer large enough to
2399 * contain the header plus one complete page of data. Otherwise, we need
2400 * to leave cifs_readpages out of the address space operations.
2401 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002402const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002403 .readpage = cifs_readpage,
2404 .writepage = cifs_writepage,
2405 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002406 .write_begin = cifs_write_begin,
2407 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002408 .set_page_dirty = __set_page_dirty_nobuffers,
2409 /* .sync_page = cifs_sync_page, */
2410 /* .direct_IO = */
2411};