blob: 71185d1d310a4499676cd162d215a810a251529b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
Steve Frenchf19159d2010-04-21 04:12:10 +00006 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include "cifsfs.h"
37#include "cifspdu.h"
38#include "cifsglob.h"
39#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42#include "cifs_fs_sb.h"
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +053043#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static inline int cifs_convert_flags(unsigned int flags)
46{
47 if ((flags & O_ACCMODE) == O_RDONLY)
48 return GENERIC_READ;
49 else if ((flags & O_ACCMODE) == O_WRONLY)
50 return GENERIC_WRITE;
51 else if ((flags & O_ACCMODE) == O_RDWR) {
52 /* GENERIC_ALL is too much permission to request
53 can cause unnecessary access denied on create */
54 /* return GENERIC_ALL; */
55 return (GENERIC_READ | GENERIC_WRITE);
56 }
57
Jeff Laytone10f7b52008-05-14 10:21:33 -070058 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
59 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
60 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000061}
Jeff Laytone10f7b52008-05-14 10:21:33 -070062
Jeff Layton608712f2010-10-15 15:33:56 -040063static u32 cifs_posix_convert_flags(unsigned int flags)
Steve French7fc8f4e2009-02-23 20:43:11 +000064{
Jeff Layton608712f2010-10-15 15:33:56 -040065 u32 posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070066
Steve French7fc8f4e2009-02-23 20:43:11 +000067 if ((flags & O_ACCMODE) == O_RDONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040068 posix_flags = SMB_O_RDONLY;
Steve French7fc8f4e2009-02-23 20:43:11 +000069 else if ((flags & O_ACCMODE) == O_WRONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040070 posix_flags = SMB_O_WRONLY;
71 else if ((flags & O_ACCMODE) == O_RDWR)
72 posix_flags = SMB_O_RDWR;
73
74 if (flags & O_CREAT)
75 posix_flags |= SMB_O_CREAT;
76 if (flags & O_EXCL)
77 posix_flags |= SMB_O_EXCL;
78 if (flags & O_TRUNC)
79 posix_flags |= SMB_O_TRUNC;
80 /* be safe and imply O_SYNC for O_DSYNC */
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010081 if (flags & O_DSYNC)
Jeff Layton608712f2010-10-15 15:33:56 -040082 posix_flags |= SMB_O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000083 if (flags & O_DIRECTORY)
Jeff Layton608712f2010-10-15 15:33:56 -040084 posix_flags |= SMB_O_DIRECTORY;
Steve French7fc8f4e2009-02-23 20:43:11 +000085 if (flags & O_NOFOLLOW)
Jeff Layton608712f2010-10-15 15:33:56 -040086 posix_flags |= SMB_O_NOFOLLOW;
Steve French7fc8f4e2009-02-23 20:43:11 +000087 if (flags & O_DIRECT)
Jeff Layton608712f2010-10-15 15:33:56 -040088 posix_flags |= SMB_O_DIRECT;
Steve French7fc8f4e2009-02-23 20:43:11 +000089
90 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091}
92
93static inline int cifs_get_disposition(unsigned int flags)
94{
95 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
96 return FILE_CREATE;
97 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
98 return FILE_OVERWRITE_IF;
99 else if ((flags & O_CREAT) == O_CREAT)
100 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000101 else if ((flags & O_TRUNC) == O_TRUNC)
102 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 else
104 return FILE_OPEN;
105}
106
Jeff Laytondb460242010-06-16 13:40:17 -0400107static inline int cifs_open_inode_helper(struct inode *inode,
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530108 struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 char *full_path, int xid)
110{
Jeff Laytondb460242010-06-16 13:40:17 -0400111 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 struct timespec temp;
113 int rc;
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (pCifsInode->clientCanCacheRead) {
116 /* we have the inode open somewhere else
117 no need to discard cache data */
118 goto client_can_cache;
119 }
120
121 /* BB need same check in cifs_create too? */
122 /* if not oplocked, invalidate inode pages if mtime or file
123 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400124 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Jeff Laytondb460242010-06-16 13:40:17 -0400125 if (timespec_equal(&inode->i_mtime, &temp) &&
126 (inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000128 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 } else {
Jeff Laytondb460242010-06-16 13:40:17 -0400130 if (inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000131 /* BB no need to lock inode until after invalidate
132 since namei code should already have it locked? */
Jeff Laytondb460242010-06-16 13:40:17 -0400133 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400134 mapping_set_error(inode->i_mapping, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000136 cFYI(1, "invalidating remote inode since open detected it "
137 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400138 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140
141client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000142 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400143 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
144 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 else
Jeff Laytondb460242010-06-16 13:40:17 -0400146 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
147 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300149 cifs_set_oplock_level(inode, oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 return rc;
152}
153
Jeff Layton608712f2010-10-15 15:33:56 -0400154int cifs_posix_open(char *full_path, struct inode **pinode,
155 struct super_block *sb, int mode, unsigned int f_flags,
156 __u32 *poplock, __u16 *pnetfid, int xid)
157{
158 int rc;
159 FILE_UNIX_BASIC_INFO *presp_data;
160 __u32 posix_flags = 0;
161 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
162 struct cifs_fattr fattr;
163 struct tcon_link *tlink;
164 struct cifsTconInfo *tcon;
165
166 cFYI(1, "posix open %s", full_path);
167
168 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
169 if (presp_data == NULL)
170 return -ENOMEM;
171
172 tlink = cifs_sb_tlink(cifs_sb);
173 if (IS_ERR(tlink)) {
174 rc = PTR_ERR(tlink);
175 goto posix_open_ret;
176 }
177
178 tcon = tlink_tcon(tlink);
179 mode &= ~current_umask();
180
181 posix_flags = cifs_posix_convert_flags(f_flags);
182 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
183 poplock, full_path, cifs_sb->local_nls,
184 cifs_sb->mnt_cifs_flags &
185 CIFS_MOUNT_MAP_SPECIAL_CHR);
186 cifs_put_tlink(tlink);
187
188 if (rc)
189 goto posix_open_ret;
190
191 if (presp_data->Type == cpu_to_le32(-1))
192 goto posix_open_ret; /* open ok, caller does qpathinfo */
193
194 if (!pinode)
195 goto posix_open_ret; /* caller does not need info */
196
197 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
198
199 /* get new inode and set it up */
200 if (*pinode == NULL) {
201 cifs_fill_uniqueid(sb, &fattr);
202 *pinode = cifs_iget(sb, &fattr);
203 if (!*pinode) {
204 rc = -ENOMEM;
205 goto posix_open_ret;
206 }
207 } else {
208 cifs_fattr_to_inode(*pinode, &fattr);
209 }
210
211posix_open_ret:
212 kfree(presp_data);
213 return rc;
214}
215
Jeff Layton15ecb432010-10-15 15:34:02 -0400216struct cifsFileInfo *
217cifs_new_fileinfo(__u16 fileHandle, struct file *file,
218 struct tcon_link *tlink, __u32 oplock)
219{
220 struct dentry *dentry = file->f_path.dentry;
221 struct inode *inode = dentry->d_inode;
222 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
223 struct cifsFileInfo *pCifsFile;
224
225 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
226 if (pCifsFile == NULL)
227 return pCifsFile;
228
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400229 pCifsFile->count = 1;
Jeff Layton15ecb432010-10-15 15:34:02 -0400230 pCifsFile->netfid = fileHandle;
231 pCifsFile->pid = current->tgid;
232 pCifsFile->uid = current_fsuid();
233 pCifsFile->dentry = dget(dentry);
234 pCifsFile->f_flags = file->f_flags;
235 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400236 pCifsFile->tlink = cifs_get_tlink(tlink);
237 mutex_init(&pCifsFile->fh_mutex);
238 mutex_init(&pCifsFile->lock_mutex);
239 INIT_LIST_HEAD(&pCifsFile->llist);
Jeff Layton15ecb432010-10-15 15:34:02 -0400240 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
241
Jeff Layton44772882010-10-15 15:34:03 -0400242 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400243 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
244 /* if readable file instance put first in list*/
245 if (file->f_mode & FMODE_READ)
246 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
247 else
248 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400249 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400250
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300251 cifs_set_oplock_level(inode, oplock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400252
253 file->private_data = pCifsFile;
254 return pCifsFile;
255}
256
Steve Frenchcdff08e2010-10-21 22:46:14 +0000257/*
258 * Release a reference on the file private data. This may involve closing
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400259 * the filehandle out on the server. Must be called without holding
260 * cifs_file_list_lock.
Steve Frenchcdff08e2010-10-21 22:46:14 +0000261 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400262void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
263{
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300264 struct inode *inode = cifs_file->dentry->d_inode;
Steve Frenchcdff08e2010-10-21 22:46:14 +0000265 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300266 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000267 struct cifsLockInfo *li, *tmp;
268
269 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400270 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000271 spin_unlock(&cifs_file_list_lock);
272 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400273 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000274
275 /* remove it from the lists */
276 list_del(&cifs_file->flist);
277 list_del(&cifs_file->tlist);
278
279 if (list_empty(&cifsi->openFileList)) {
280 cFYI(1, "closing last open instance for inode %p",
281 cifs_file->dentry->d_inode);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300282 cifs_set_oplock_level(inode, 0);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000283 }
284 spin_unlock(&cifs_file_list_lock);
285
286 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
287 int xid, rc;
288
289 xid = GetXid();
290 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
291 FreeXid(xid);
292 }
293
294 /* Delete any outstanding lock records. We'll lose them when the file
295 * is closed anyway.
296 */
297 mutex_lock(&cifs_file->lock_mutex);
298 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
299 list_del(&li->llist);
300 kfree(li);
301 }
302 mutex_unlock(&cifs_file->lock_mutex);
303
304 cifs_put_tlink(cifs_file->tlink);
305 dput(cifs_file->dentry);
306 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400307}
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309int cifs_open(struct inode *inode, struct file *file)
310{
311 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400312 int xid;
313 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000315 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400316 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400317 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 char *full_path = NULL;
320 int desiredAccess;
321 int disposition;
322 __u16 netfid;
323 FILE_ALL_INFO *buf = NULL;
324
325 xid = GetXid();
326
327 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400328 tlink = cifs_sb_tlink(cifs_sb);
329 if (IS_ERR(tlink)) {
330 FreeXid(xid);
331 return PTR_ERR(tlink);
332 }
333 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Steve Frencha6ce4932009-04-09 01:14:32 +0000335 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800337 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530339 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400340 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342
Joe Perchesb6b38f72010-04-21 03:50:45 +0000343 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
344 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000345
346 if (oplockEnabled)
347 oplock = REQ_OPLOCK;
348 else
349 oplock = 0;
350
Steve French64cc2c62009-03-04 19:54:08 +0000351 if (!tcon->broken_posix_open && tcon->unix_ext &&
352 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000353 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
354 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000355 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400356 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000357 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400358 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000359 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000360 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400361
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400362 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
363 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400364 if (pCifsFile == NULL) {
365 CIFSSMBClose(xid, tcon, netfid);
366 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400367 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530368
369 cifs_fscache_set_inode_cookie(inode, file);
370
Steve French276a74a2009-03-03 18:00:34 +0000371 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000372 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
373 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000374 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000375 " unexpected error on SMB posix open"
376 ", disabling posix open support."
377 " Check if server update available.",
378 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000379 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000380 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000381 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
382 (rc != -EOPNOTSUPP)) /* path not found or net err */
383 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000384 /* else fallthrough to retry open the old way on network i/o
385 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000386 }
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 desiredAccess = cifs_convert_flags(file->f_flags);
389
390/*********************************************************************
391 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000392 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000394 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 * O_CREAT FILE_OPEN_IF
396 * O_CREAT | O_EXCL FILE_CREATE
397 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
398 * O_TRUNC FILE_OVERWRITE
399 * none of the above FILE_OPEN
400 *
401 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000402 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 * O_CREAT | O_TRUNC is similar but truncates the existing
404 * file rather than creating a new file as FILE_SUPERSEDE does
405 * (which uses the attributes / metadata passed in on open call)
406 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000407 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 *? and the read write flags match reasonably. O_LARGEFILE
409 *? is irrelevant because largefile support is always used
410 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
411 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
412 *********************************************************************/
413
414 disposition = cifs_get_disposition(file->f_flags);
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 /* BB pass O_SYNC flag through on file attributes .. BB */
417
418 /* Also refresh inode by passing in file_info buf returned by SMBOpen
419 and calling get_inode_info with returned buf (at least helps
420 non-Unix server case) */
421
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000422 /* BB we can not do this if this is the second open of a file
423 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
425 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
426 if (!buf) {
427 rc = -ENOMEM;
428 goto out;
429 }
Steve French5bafd762006-06-07 00:18:43 +0000430
Jeff Laytona6e8a842010-09-20 16:01:33 -0700431 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000432 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000433 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700434 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
435 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000436 else
437 rc = -EIO; /* no NT SMB support fall into legacy open below */
438
Steve Frencha9d02ad2005-08-24 23:06:05 -0700439 if (rc == -EIO) {
440 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000441 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700442 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
443 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
444 & CIFS_MOUNT_MAP_SPECIAL_CHR);
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000447 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 goto out;
449 }
Jeff Layton3321b792009-09-25 09:53:37 -0400450
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530451 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400452 if (rc != 0)
453 goto out;
454
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400455 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400456 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 rc = -ENOMEM;
458 goto out;
459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530461 cifs_fscache_set_inode_cookie(inode, file);
462
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 /* time to set mode which we can not set earlier due to
465 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000466 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400467 struct cifs_unix_set_info_args args = {
468 .mode = inode->i_mode,
469 .uid = NO_CHANGE_64,
470 .gid = NO_CHANGE_64,
471 .ctime = NO_CHANGE_64,
472 .atime = NO_CHANGE_64,
473 .mtime = NO_CHANGE_64,
474 .device = 0,
475 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400476 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
477 cifs_sb->local_nls,
478 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700479 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481 }
482
483out:
484 kfree(buf);
485 kfree(full_path);
486 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400487 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return rc;
489}
490
Adrian Bunk04187262006-06-30 18:23:04 +0200491/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492/* to server was lost */
493static int cifs_relock_file(struct cifsFileInfo *cifsFile)
494{
495 int rc = 0;
496
497/* BB list all locks open on this file and relock */
498
499 return rc;
500}
501
Jeff Layton15886172010-10-15 15:33:59 -0400502static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400505 int xid;
506 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000508 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000510 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 char *full_path = NULL;
512 int desiredAccess;
513 int disposition = FILE_OPEN;
514 __u16 netfid;
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400517 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000518 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400519 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530520 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530522 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524
Jeff Layton15886172010-10-15 15:33:59 -0400525 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400527 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529/* can not grab rename sem here because various ops, including
530 those that already have the rename sem can end up causing writepage
531 to get called and if the server was down that means we end up here,
532 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400533 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000535 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400536 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000538 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
540
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400542 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 if (oplockEnabled)
545 oplock = REQ_OPLOCK;
546 else
Steve French4b18f2a2008-04-29 00:06:05 +0000547 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Steve French7fc8f4e2009-02-23 20:43:11 +0000549 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
550 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
551 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400552
553 /*
554 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
555 * original open. Must mask them off for a reopen.
556 */
Jeff Layton15886172010-10-15 15:33:59 -0400557 unsigned int oflags = pCifsFile->f_flags &
558 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400559
Jeff Layton2422f672010-06-16 13:40:16 -0400560 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000561 cifs_sb->mnt_file_mode /* ignored */,
562 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000563 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000564 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000565 goto reopen_success;
566 }
567 /* fallthrough to retry open the old way on errors, especially
568 in the reconnect path it is important to retry hard */
569 }
570
Jeff Layton15886172010-10-15 15:33:59 -0400571 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 by SMBOpen and then calling get_inode_info with returned buf
575 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 and server version of file size can be stale. If we knew for sure
577 that inode was not dirty locally we could do this */
578
Steve French7fc8f4e2009-02-23 20:43:11 +0000579 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000581 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700582 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400584 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000585 cFYI(1, "cifs_open returned 0x%x", rc);
586 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400587 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
Jeff Layton15886172010-10-15 15:33:59 -0400589
590reopen_success:
591 pCifsFile->netfid = netfid;
592 pCifsFile->invalidHandle = false;
593 mutex_unlock(&pCifsFile->fh_mutex);
594 pCifsInode = CIFS_I(inode);
595
596 if (can_flush) {
597 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400598 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400599
Jeff Layton15886172010-10-15 15:33:59 -0400600 if (tcon->unix_ext)
601 rc = cifs_get_inode_info_unix(&inode,
602 full_path, inode->i_sb, xid);
603 else
604 rc = cifs_get_inode_info(&inode,
605 full_path, NULL, inode->i_sb,
606 xid, NULL);
607 } /* else we are writing out data to server already
608 and could deadlock if we tried to flush data, and
609 since we do not know if we have data that would
610 invalidate the current end of file on the server
611 we can not go to the server to get the new inod
612 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300613
614 cifs_set_oplock_level(inode, oplock);
615
Jeff Layton15886172010-10-15 15:33:59 -0400616 cifs_relock_file(pCifsFile);
617
618reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 kfree(full_path);
620 FreeXid(xid);
621 return rc;
622}
623
624int cifs_close(struct inode *inode, struct file *file)
625{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000626 cifsFileInfo_put(file->private_data);
627 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Steve Frenchcdff08e2010-10-21 22:46:14 +0000629 /* return code from the ->release op is always ignored */
630 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633int cifs_closedir(struct inode *inode, struct file *file)
634{
635 int rc = 0;
636 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700637 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 char *ptmp;
639
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 xid = GetXid();
643
644 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400645 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400648 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000649 if (!pCFileStruct->srch_inf.endOfSearch &&
650 !pCFileStruct->invalidHandle) {
651 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400652 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cFYI(1, "Closing uncompleted readdir with rc %d",
655 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* not much we can do if it fails anyway, ignore rc */
657 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000658 } else
Jeff Layton44772882010-10-15 15:34:03 -0400659 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
661 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000664 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000665 cifs_small_buf_release(ptmp);
666 else
667 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400669 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 kfree(file->private_data);
671 file->private_data = NULL;
672 }
673 /* BB can we lock the filestruct while this is going on? */
674 FreeXid(xid);
675 return rc;
676}
677
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000678static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
679 __u64 offset, __u8 lockType)
680{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000681 struct cifsLockInfo *li =
682 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000683 if (li == NULL)
684 return -ENOMEM;
685 li->offset = offset;
686 li->length = len;
687 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000688 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000689 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000690 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000691 return 0;
692}
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
695{
696 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 __u32 numLock = 0;
698 __u32 numUnlock = 0;
699 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000700 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000702 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000703 __u16 netfid;
704 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000705 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 length = 1 + pfLock->fl_end - pfLock->fl_start;
708 rc = -EACCES;
709 xid = GetXid();
710
Joe Perchesb6b38f72010-04-21 03:50:45 +0000711 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000713 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000717 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000719 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000721 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000722 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000725 cFYI(1, "Process suspended by mandatory locking - "
726 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000728 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000729 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000731 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000734 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 numLock = 1;
736 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000737 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000739 /* Check if unlock includes more than
740 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000742 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 lockType |= LOCKING_ANDX_SHARED_LOCK;
744 numLock = 1;
745 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000746 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 numLock = 1;
748 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000749 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 lockType |= LOCKING_ANDX_SHARED_LOCK;
751 numLock = 1;
752 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800755 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400756 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530759 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530761 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Steve French08547b02006-02-28 22:39:25 +0000763 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Steve French13a6e422008-12-02 17:24:33 +0000765 if ((tcon->ses->capabilities & CAP_UNIX) &&
766 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000767 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000768 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000769 /* BB add code here to normalize offset and length to
770 account for negative length which we can not accept over the
771 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000773 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000774 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000775 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000776 posix_lock_type = CIFS_RDLCK;
777 else
778 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000779 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000780 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000781 posix_lock_type, wait_flag);
782 FreeXid(xid);
783 return rc;
784 }
785
786 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000787 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000788 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000790 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 pfLock->fl_start, 1 /* numUnlock */ ,
792 0 /* numLock */ , lockType,
793 0 /* wait flag */ );
794 pfLock->fl_type = F_UNLCK;
795 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000796 cERROR(1, "Error unlocking previously locked "
797 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 rc = 0;
799
800 } else {
801 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400802 rc = 0;
803
804 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
805 pfLock->fl_type = F_WRLCK;
806 } else {
807 rc = CIFSSMBLock(xid, tcon, netfid, length,
808 pfLock->fl_start, 0, 1,
809 lockType | LOCKING_ANDX_SHARED_LOCK,
810 0 /* wait flag */);
811 if (rc == 0) {
812 rc = CIFSSMBLock(xid, tcon, netfid,
813 length, pfLock->fl_start, 1, 0,
814 lockType |
815 LOCKING_ANDX_SHARED_LOCK,
816 0 /* wait flag */);
817 pfLock->fl_type = F_RDLCK;
818 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000819 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400820 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000821 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400822 rc = 0;
823 } else {
824 pfLock->fl_type = F_WRLCK;
825 rc = 0;
826 }
827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829
830 FreeXid(xid);
831 return rc;
832 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000833
834 if (!numLock && !numUnlock) {
835 /* if no lock or unlock then nothing
836 to do since we do not know what it is */
837 FreeXid(xid);
838 return -EOPNOTSUPP;
839 }
840
841 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000842 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000843 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000844 posix_lock_type = CIFS_RDLCK;
845 else
846 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000847
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000848 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000849 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000850
Steve French13a6e422008-12-02 17:24:33 +0000851 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000852 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000853 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000854 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700855 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000856
857 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000858 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000859 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000860 0, numLock, lockType, wait_flag);
861
862 if (rc == 0) {
863 /* For Windows locks we must store them. */
864 rc = store_file_lock(fid, length,
865 pfLock->fl_start, lockType);
866 }
867 } else if (numUnlock) {
868 /* For each stored lock that this unlock overlaps
869 completely, unlock it. */
870 int stored_rc = 0;
871 struct cifsLockInfo *li, *tmp;
872
Steve French6b70c952006-09-21 07:35:29 +0000873 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000874 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000875 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
876 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000877 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000878 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000879 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000880 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000881 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000882 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 if (stored_rc)
884 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000885 else {
886 list_del(&li->llist);
887 kfree(li);
888 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000889 }
890 }
Roland Dreier796e5662007-05-03 04:33:45 +0000891 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000892 }
893 }
894
Steve Frenchd634cc12005-08-26 14:42:59 -0500895 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 posix_lock_file_wait(file, pfLock);
897 FreeXid(xid);
898 return rc;
899}
900
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400901/*
902 * Set the timeout on write requests past EOF. For some servers (Windows)
903 * these calls can be very long.
904 *
905 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
906 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
907 * The 10M cutoff is totally arbitrary. A better scheme for this would be
908 * welcome if someone wants to suggest one.
909 *
910 * We may be able to do a better job with this if there were some way to
911 * declare that a file should be sparse.
912 */
913static int
914cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
915{
916 if (offset <= cifsi->server_eof)
917 return CIFS_STD_OP;
918 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
919 return CIFS_VLONG_OP;
920 else
921 return CIFS_LONG_OP;
922}
923
924/* update the file size (if needed) after a write */
925static void
926cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
927 unsigned int bytes_written)
928{
929 loff_t end_of_write = offset + bytes_written;
930
931 if (end_of_write > cifsi->server_eof)
932 cifsi->server_eof = end_of_write;
933}
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935ssize_t cifs_user_write(struct file *file, const char __user *write_data,
936 size_t write_size, loff_t *poffset)
937{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100938 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 int rc = 0;
940 unsigned int bytes_written = 0;
941 unsigned int total_written;
942 struct cifs_sb_info *cifs_sb;
943 struct cifsTconInfo *pTcon;
944 int xid, long_op;
945 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100946 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800948 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Joe Perchesb6b38f72010-04-21 03:50:45 +0000950 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
951 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 if (file->private_data == NULL)
954 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700955
Joe Perchesc21dfb62010-07-12 13:50:14 -0700956 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400957 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000958
Jeff Layton838726c2008-08-28 07:54:59 -0400959 rc = generic_write_checks(file, poffset, &write_size, 0);
960 if (rc)
961 return rc;
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400965 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 for (total_written = 0; write_size > total_written;
967 total_written += bytes_written) {
968 rc = -EAGAIN;
969 while (rc == -EAGAIN) {
970 if (file->private_data == NULL) {
971 /* file has been closed on us */
972 FreeXid(xid);
973 /* if we have gotten here we have written some data
974 and blocked, and the file has been freed on us while
975 we blocked so return what we managed to write */
976 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 /* we could deadlock if we called
980 filemap_fdatawait from here so tell
981 reopen_file not to flush data to server
982 now */
Jeff Layton15886172010-10-15 15:33:59 -0400983 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (rc != 0)
985 break;
986 }
987
988 rc = CIFSSMBWrite(xid, pTcon,
989 open_file->netfid,
990 min_t(const int, cifs_sb->wsize,
991 write_size - total_written),
992 *poffset, &bytes_written,
993 NULL, write_data + total_written, long_op);
994 }
995 if (rc || (bytes_written == 0)) {
996 if (total_written)
997 break;
998 else {
999 FreeXid(xid);
1000 return rc;
1001 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001002 } else {
1003 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001005 }
Steve French133672e2007-11-13 22:41:37 +00001006 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 15 seconds is plenty */
1008 }
1009
Steve Frencha4544342005-08-24 13:59:35 -07001010 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001012/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001013 * inode->i_ctime = inode->i_mtime =
1014 * current_fs_time(inode->i_sb);*/
1015 if (total_written > 0) {
1016 spin_lock(&inode->i_lock);
1017 if (*poffset > inode->i_size)
1018 i_size_write(inode, *poffset);
1019 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001021 mark_inode_dirty_sync(inode);
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 FreeXid(xid);
1024 return total_written;
1025}
1026
Jeff Layton7da4b492010-10-15 15:34:00 -04001027static ssize_t cifs_write(struct cifsFileInfo *open_file,
1028 const char *write_data, size_t write_size,
1029 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
1031 int rc = 0;
1032 unsigned int bytes_written = 0;
1033 unsigned int total_written;
1034 struct cifs_sb_info *cifs_sb;
1035 struct cifsTconInfo *pTcon;
1036 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001037 struct dentry *dentry = open_file->dentry;
1038 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Jeff Layton7da4b492010-10-15 15:34:00 -04001040 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Joe Perchesb6b38f72010-04-21 03:50:45 +00001042 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001043 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Jeff Layton13cfb732010-09-29 19:51:11 -04001045 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001049 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 for (total_written = 0; write_size > total_written;
1051 total_written += bytes_written) {
1052 rc = -EAGAIN;
1053 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 /* we could deadlock if we called
1056 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001057 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001059 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 if (rc != 0)
1061 break;
1062 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001063 if (experimEnabled || (pTcon->ses->server &&
1064 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001065 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001066 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001067 struct kvec iov[2];
1068 unsigned int len;
1069
Steve French0ae0efa2005-10-10 10:57:19 -07001070 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001071 write_size - total_written);
1072 /* iov[0] is reserved for smb header */
1073 iov[1].iov_base = (char *)write_data +
1074 total_written;
1075 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001076 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001077 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001078 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001079 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001080 } else
Steve French60808232006-04-22 15:53:05 +00001081 rc = CIFSSMBWrite(xid, pTcon,
1082 open_file->netfid,
1083 min_t(const int, cifs_sb->wsize,
1084 write_size - total_written),
1085 *poffset, &bytes_written,
1086 write_data + total_written,
1087 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089 if (rc || (bytes_written == 0)) {
1090 if (total_written)
1091 break;
1092 else {
1093 FreeXid(xid);
1094 return rc;
1095 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001096 } else {
1097 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001099 }
Steve French133672e2007-11-13 22:41:37 +00001100 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 15 seconds is plenty */
1102 }
1103
Steve Frencha4544342005-08-24 13:59:35 -07001104 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jeff Layton7da4b492010-10-15 15:34:00 -04001106 if (total_written > 0) {
1107 spin_lock(&dentry->d_inode->i_lock);
1108 if (*poffset > dentry->d_inode->i_size)
1109 i_size_write(dentry->d_inode, *poffset);
1110 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001112 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 FreeXid(xid);
1114 return total_written;
1115}
1116
Steve French630f3f0c2007-10-25 21:17:17 +00001117#ifdef CONFIG_CIFS_EXPERIMENTAL
Jeff Layton6508d902010-09-29 19:51:11 -04001118struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1119 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001120{
1121 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001122 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1123
1124 /* only filter by fsuid on multiuser mounts */
1125 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1126 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001127
Jeff Layton44772882010-10-15 15:34:03 -04001128 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001129 /* we could simply get the first_list_entry since write-only entries
1130 are always at the end of the list but since the first entry might
1131 have a close pending, we go through the whole list */
1132 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001133 if (fsuid_only && open_file->uid != current_fsuid())
1134 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001135 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001136 if (!open_file->invalidHandle) {
1137 /* found a good file */
1138 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001139 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001140 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001141 return open_file;
1142 } /* else might as well continue, and look for
1143 another, or simply have the caller reopen it
1144 again rather than trying to fix this handle */
1145 } else /* write only file */
1146 break; /* write only files are last so must be done */
1147 }
Jeff Layton44772882010-10-15 15:34:03 -04001148 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001149 return NULL;
1150}
1151#endif
1152
Jeff Layton6508d902010-09-29 19:51:11 -04001153struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1154 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001155{
1156 struct cifsFileInfo *open_file;
Jeff Layton6508d902010-09-29 19:51:11 -04001157 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
Jeff Layton2846d382008-09-22 21:33:33 -04001158 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001159 int rc;
Steve French6148a742005-10-05 12:23:19 -07001160
Steve French60808232006-04-22 15:53:05 +00001161 /* Having a null inode here (because mapping->host was set to zero by
1162 the VFS or MM) should not happen but we had reports of on oops (due to
1163 it being zero) during stress testcases so we need to check for it */
1164
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001165 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001166 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001167 dump_stack();
1168 return NULL;
1169 }
1170
Jeff Layton6508d902010-09-29 19:51:11 -04001171 /* only filter by fsuid on multiuser mounts */
1172 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1173 fsuid_only = false;
1174
Jeff Layton44772882010-10-15 15:34:03 -04001175 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001176refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001177 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001178 if (!any_available && open_file->pid != current->tgid)
1179 continue;
1180 if (fsuid_only && open_file->uid != current_fsuid())
1181 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001182 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001183 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001184
1185 if (!open_file->invalidHandle) {
1186 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001187 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001188 return open_file;
1189 }
Steve French8840dee2007-11-16 23:05:52 +00001190
Jeff Layton44772882010-10-15 15:34:03 -04001191 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001192
Steve French9b22b0b2007-10-02 01:11:08 +00001193 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001194 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001195 if (!rc)
1196 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001197
Steve Frenchcdff08e2010-10-21 22:46:14 +00001198 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001199 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001200 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001201
Steve Frenchcdff08e2010-10-21 22:46:14 +00001202 spin_lock(&cifs_file_list_lock);
1203
Steve French9b22b0b2007-10-02 01:11:08 +00001204 /* else we simply continue to the next entry. Thus
1205 we do not loop on reopen errors. If we
1206 can not reopen the file, for example if we
1207 reconnected to a server with another client
1208 racing to delete or lock the file we would not
1209 make progress if we restarted before the beginning
1210 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001211 }
1212 }
Jeff Layton2846d382008-09-22 21:33:33 -04001213 /* couldn't find useable FH with same pid, try any available */
1214 if (!any_available) {
1215 any_available = true;
1216 goto refind_writable;
1217 }
Jeff Layton44772882010-10-15 15:34:03 -04001218 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001219 return NULL;
1220}
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1223{
1224 struct address_space *mapping = page->mapping;
1225 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1226 char *write_data;
1227 int rc = -EFAULT;
1228 int bytes_written = 0;
1229 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001231 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 if (!mapping || !mapping->host)
1234 return -EFAULT;
1235
1236 inode = page->mapping->host;
1237 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 offset += (loff_t)from;
1240 write_data = kmap(page);
1241 write_data += from;
1242
1243 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1244 kunmap(page);
1245 return -EIO;
1246 }
1247
1248 /* racing with truncate? */
1249 if (offset > mapping->host->i_size) {
1250 kunmap(page);
1251 return 0; /* don't care */
1252 }
1253
1254 /* check to make sure that we are not extending the file */
1255 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001256 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Jeff Layton6508d902010-09-29 19:51:11 -04001258 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001259 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001260 bytes_written = cifs_write(open_file, write_data,
1261 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001262 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001264 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001265 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001266 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001267 else if (bytes_written < 0)
1268 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001269 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001270 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 rc = -EIO;
1272 }
1273
1274 kunmap(page);
1275 return rc;
1276}
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001279 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280{
Steve French37c0eb42005-10-05 14:50:29 -07001281 unsigned int bytes_to_write;
1282 unsigned int bytes_written;
1283 struct cifs_sb_info *cifs_sb;
1284 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001285 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001286 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001287 int range_whole = 0;
1288 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001289 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001290 int n_iov = 0;
1291 pgoff_t next;
1292 int nr_pages;
1293 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001294 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001295 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001296 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001297 struct page *page;
1298 struct pagevec pvec;
1299 int rc = 0;
1300 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001301 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Steve French37c0eb42005-10-05 14:50:29 -07001303 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001304
Steve French37c0eb42005-10-05 14:50:29 -07001305 /*
1306 * If wsize is smaller that the page cache size, default to writing
1307 * one page at a time via cifs_writepage
1308 */
1309 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1310 return generic_writepages(mapping, wbc);
1311
Steve French9a0c8232007-02-02 04:21:57 +00001312 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001313 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001314 return generic_writepages(mapping, wbc);
1315
Steve French37c0eb42005-10-05 14:50:29 -07001316 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001317 * if there's no open file, then this is likely to fail too,
1318 * but it'll at least handle the return. Maybe it should be
1319 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001320 */
Jeff Layton6508d902010-09-29 19:51:11 -04001321 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001322 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001323 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001324 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001325 }
1326
Jeff Layton13cfb732010-09-29 19:51:11 -04001327 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001328 if (!experimEnabled && tcon->ses->server->secMode &
1329 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1330 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001331 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001332 return generic_writepages(mapping, wbc);
1333 }
1334 cifsFileInfo_put(open_file);
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 xid = GetXid();
1337
Steve French37c0eb42005-10-05 14:50:29 -07001338 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001339 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001340 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001341 end = -1;
1342 } else {
1343 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1344 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1345 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1346 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001347 scanned = 1;
1348 }
1349retry:
1350 while (!done && (index <= end) &&
1351 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1352 PAGECACHE_TAG_DIRTY,
1353 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1354 int first;
1355 unsigned int i;
1356
Steve French37c0eb42005-10-05 14:50:29 -07001357 first = -1;
1358 next = 0;
1359 n_iov = 0;
1360 bytes_to_write = 0;
1361
1362 for (i = 0; i < nr_pages; i++) {
1363 page = pvec.pages[i];
1364 /*
1365 * At this point we hold neither mapping->tree_lock nor
1366 * lock on the page itself: the page may be truncated or
1367 * invalidated (changing page->mapping to NULL), or even
1368 * swizzled back from swapper_space to tmpfs file
1369 * mapping
1370 */
1371
1372 if (first < 0)
1373 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001374 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001375 break;
1376
1377 if (unlikely(page->mapping != mapping)) {
1378 unlock_page(page);
1379 break;
1380 }
1381
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001382 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001383 done = 1;
1384 unlock_page(page);
1385 break;
1386 }
1387
1388 if (next && (page->index != next)) {
1389 /* Not next consecutive page */
1390 unlock_page(page);
1391 break;
1392 }
1393
1394 if (wbc->sync_mode != WB_SYNC_NONE)
1395 wait_on_page_writeback(page);
1396
1397 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001398 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001399 unlock_page(page);
1400 break;
1401 }
Steve French84d2f072005-10-12 15:32:05 -07001402
Linus Torvaldscb876f42006-12-23 16:19:07 -08001403 /*
1404 * This actually clears the dirty bit in the radix tree.
1405 * See cifs_writepage() for more commentary.
1406 */
1407 set_page_writeback(page);
1408
Steve French84d2f072005-10-12 15:32:05 -07001409 if (page_offset(page) >= mapping->host->i_size) {
1410 done = 1;
1411 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001412 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001413 break;
1414 }
1415
Steve French37c0eb42005-10-05 14:50:29 -07001416 /*
1417 * BB can we get rid of this? pages are held by pvec
1418 */
1419 page_cache_get(page);
1420
Steve French84d2f072005-10-12 15:32:05 -07001421 len = min(mapping->host->i_size - page_offset(page),
1422 (loff_t)PAGE_CACHE_SIZE);
1423
Steve French37c0eb42005-10-05 14:50:29 -07001424 /* reserve iov[0] for the smb header */
1425 n_iov++;
1426 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001427 iov[n_iov].iov_len = len;
1428 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001429
1430 if (first < 0) {
1431 first = i;
1432 offset = page_offset(page);
1433 }
1434 next = page->index + 1;
1435 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1436 break;
1437 }
1438 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001439 open_file = find_writable_file(CIFS_I(mapping->host),
1440 false);
Steve French23e7dd72005-10-20 13:44:56 -07001441 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001442 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001443 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001444 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001445 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001446 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001447 bytes_to_write, offset,
1448 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001449 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001450 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001451 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001452 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001453
1454 if (rc || bytes_written < bytes_to_write) {
1455 cERROR(1, "Write2 ret %d, wrote %d",
1456 rc, bytes_written);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001457 mapping_set_error(mapping, rc);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001458 } else {
1459 cifs_stats_bytes_written(tcon, bytes_written);
1460 }
1461
Steve French37c0eb42005-10-05 14:50:29 -07001462 for (i = 0; i < n_iov; i++) {
1463 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001464 /* Should we also set page error on
1465 success rc but too little data written? */
1466 /* BB investigate retry logic on temporary
1467 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001468 when page marked as error */
1469 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001470 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001471 kunmap(page);
1472 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001473 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001474 page_cache_release(page);
1475 }
1476 if ((wbc->nr_to_write -= n_iov) <= 0)
1477 done = 1;
1478 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001479 } else
1480 /* Need to re-find the pages we skipped */
1481 index = pvec.pages[0]->index + 1;
1482
Steve French37c0eb42005-10-05 14:50:29 -07001483 pagevec_release(&pvec);
1484 }
1485 if (!scanned && !done) {
1486 /*
1487 * We hit the last page and there is more work to be done: wrap
1488 * back to the start of the file
1489 */
1490 scanned = 1;
1491 index = 0;
1492 goto retry;
1493 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001494 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001495 mapping->writeback_index = index;
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001498 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 return rc;
1500}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001502static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503{
1504 int rc = -EFAULT;
1505 int xid;
1506
1507 xid = GetXid();
1508/* BB add check for wbc flags */
1509 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001510 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001511 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001512
1513 /*
1514 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1515 *
1516 * A writepage() implementation always needs to do either this,
1517 * or re-dirty the page with "redirty_page_for_writepage()" in
1518 * the case of a failure.
1519 *
1520 * Just unlocking the page will cause the radix tree tag-bits
1521 * to fail to update with the state of the page correctly.
1522 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001523 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1525 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1526 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001527 end_page_writeback(page);
1528 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 FreeXid(xid);
1530 return rc;
1531}
1532
Nick Piggind9414772008-09-24 11:32:59 -04001533static int cifs_write_end(struct file *file, struct address_space *mapping,
1534 loff_t pos, unsigned len, unsigned copied,
1535 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
Nick Piggind9414772008-09-24 11:32:59 -04001537 int rc;
1538 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Joe Perchesb6b38f72010-04-21 03:50:45 +00001540 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1541 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001542
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001543 if (PageChecked(page)) {
1544 if (copied == len)
1545 SetPageUptodate(page);
1546 ClearPageChecked(page);
1547 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001548 SetPageUptodate(page);
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001551 char *page_data;
1552 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1553 int xid;
1554
1555 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 /* this is probably better than directly calling
1557 partialpage_write since in this function the file handle is
1558 known which we might as well leverage */
1559 /* BB check if anything else missing out of ppw
1560 such as updating last write time */
1561 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001562 rc = cifs_write(file->private_data, page_data + offset,
1563 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001564 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001566
1567 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001568 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001569 rc = copied;
1570 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 set_page_dirty(page);
1572 }
1573
Nick Piggind9414772008-09-24 11:32:59 -04001574 if (rc > 0) {
1575 spin_lock(&inode->i_lock);
1576 if (pos > inode->i_size)
1577 i_size_write(inode, pos);
1578 spin_unlock(&inode->i_lock);
1579 }
1580
1581 unlock_page(page);
1582 page_cache_release(page);
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 return rc;
1585}
1586
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001587int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588{
1589 int xid;
1590 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001591 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001592 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001593 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 xid = GetXid();
1596
Joe Perchesb6b38f72010-04-21 03:50:45 +00001597 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001598 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001599
Jeff Laytoncea21802007-11-20 23:19:03 +00001600 rc = filemap_write_and_wait(inode->i_mapping);
1601 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001602 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1603
Jeff Layton13cfb732010-09-29 19:51:11 -04001604 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001605 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001606 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001607 }
Steve Frenchb298f222009-02-21 21:17:43 +00001608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 FreeXid(xid);
1610 return rc;
1611}
1612
NeilBrown3978d712006-03-26 01:37:17 -08001613/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
1615 struct address_space *mapping;
1616 struct inode *inode;
1617 unsigned long index = page->index;
1618 unsigned int rpages = 0;
1619 int rc = 0;
1620
Steve Frenchf19159d2010-04-21 04:12:10 +00001621 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 mapping = page->mapping;
1623 if (!mapping)
1624 return 0;
1625 inode = mapping->host;
1626 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001627 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001629/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1631
Joe Perchesb6b38f72010-04-21 03:50:45 +00001632/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
NeilBrown3978d712006-03-26 01:37:17 -08001634#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 if (rc < 0)
1636 return rc;
1637 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001638#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639} */
1640
1641/*
1642 * As file closes, flush all cached write data for this inode checking
1643 * for write behind errors.
1644 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001645int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001647 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 int rc = 0;
1649
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001650 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001651 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001652
Joe Perchesb6b38f72010-04-21 03:50:45 +00001653 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 return rc;
1656}
1657
1658ssize_t cifs_user_read(struct file *file, char __user *read_data,
1659 size_t read_size, loff_t *poffset)
1660{
1661 int rc = -EACCES;
1662 unsigned int bytes_read = 0;
1663 unsigned int total_read = 0;
1664 unsigned int current_read_size;
1665 struct cifs_sb_info *cifs_sb;
1666 struct cifsTconInfo *pTcon;
1667 int xid;
1668 struct cifsFileInfo *open_file;
1669 char *smb_read_data;
1670 char __user *current_offset;
1671 struct smb_com_read_rsp *pSMBr;
1672
1673 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001674 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
1676 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301677 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301679 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001681 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001682 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
Steve Frenchad7a2922008-02-07 23:25:02 +00001684 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001685 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 for (total_read = 0, current_offset = read_data;
1688 read_size > total_read;
1689 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001690 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 cifs_sb->rsize);
1692 rc = -EAGAIN;
1693 smb_read_data = NULL;
1694 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001695 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001696 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001697 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (rc != 0)
1699 break;
1700 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001701 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001702 open_file->netfid,
1703 current_read_size, *poffset,
1704 &bytes_read, &smb_read_data,
1705 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001708 if (copy_to_user(current_offset,
1709 smb_read_data +
1710 4 /* RFC1001 length field */ +
1711 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001712 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001713 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001714
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001715 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001716 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001717 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001718 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 smb_read_data = NULL;
1720 }
1721 }
1722 if (rc || (bytes_read == 0)) {
1723 if (total_read) {
1724 break;
1725 } else {
1726 FreeXid(xid);
1727 return rc;
1728 }
1729 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001730 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 *poffset += bytes_read;
1732 }
1733 }
1734 FreeXid(xid);
1735 return total_read;
1736}
1737
1738
1739static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1740 loff_t *poffset)
1741{
1742 int rc = -EACCES;
1743 unsigned int bytes_read = 0;
1744 unsigned int total_read;
1745 unsigned int current_read_size;
1746 struct cifs_sb_info *cifs_sb;
1747 struct cifsTconInfo *pTcon;
1748 int xid;
1749 char *current_offset;
1750 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001751 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001754 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301757 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301759 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001761 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001762 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
1764 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001765 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001767 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 read_size > total_read;
1769 total_read += bytes_read, current_offset += bytes_read) {
1770 current_read_size = min_t(const int, read_size - total_read,
1771 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001772 /* For windows me and 9x we do not want to request more
1773 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001774 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001775 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1776 current_read_size = min_t(const int, current_read_size,
1777 pTcon->ses->server->maxBuf - 128);
1778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 rc = -EAGAIN;
1780 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001781 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001782 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 if (rc != 0)
1784 break;
1785 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001786 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001787 open_file->netfid,
1788 current_read_size, *poffset,
1789 &bytes_read, &current_offset,
1790 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
1792 if (rc || (bytes_read == 0)) {
1793 if (total_read) {
1794 break;
1795 } else {
1796 FreeXid(xid);
1797 return rc;
1798 }
1799 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001800 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 *poffset += bytes_read;
1802 }
1803 }
1804 FreeXid(xid);
1805 return total_read;
1806}
1807
1808int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1809{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 int rc, xid;
1811
1812 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001813 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001815 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 FreeXid(xid);
1817 return rc;
1818 }
1819 rc = generic_file_mmap(file, vma);
1820 FreeXid(xid);
1821 return rc;
1822}
1823
1824
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001825static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001826 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827{
1828 struct page *page;
1829 char *target;
1830
1831 while (bytes_read > 0) {
1832 if (list_empty(pages))
1833 break;
1834
1835 page = list_entry(pages->prev, struct page, lru);
1836 list_del(&page->lru);
1837
Nick Piggin315e9952010-04-21 03:18:28 +00001838 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 GFP_KERNEL)) {
1840 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001841 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001842 data += PAGE_CACHE_SIZE;
1843 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 continue;
1845 }
Jeff Layton06b43672010-06-01 10:54:45 -04001846 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001848 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850 if (PAGE_CACHE_SIZE > bytes_read) {
1851 memcpy(target, data, bytes_read);
1852 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001853 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 PAGE_CACHE_SIZE - bytes_read);
1855 bytes_read = 0;
1856 } else {
1857 memcpy(target, data, PAGE_CACHE_SIZE);
1858 bytes_read -= PAGE_CACHE_SIZE;
1859 }
1860 kunmap_atomic(target, KM_USER0);
1861
1862 flush_dcache_page(page);
1863 SetPageUptodate(page);
1864 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301866
1867 /* add page to FS-Cache */
1868 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 }
1870 return;
1871}
1872
1873static int cifs_readpages(struct file *file, struct address_space *mapping,
1874 struct list_head *page_list, unsigned num_pages)
1875{
1876 int rc = -EACCES;
1877 int xid;
1878 loff_t offset;
1879 struct page *page;
1880 struct cifs_sb_info *cifs_sb;
1881 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001882 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001883 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 char *smb_read_data = NULL;
1885 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001887 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 xid = GetXid();
1890 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301891 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301893 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001895 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001896 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001897 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001898
Suresh Jayaraman56698232010-07-05 18:13:25 +05301899 /*
1900 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1901 * immediately if the cookie is negative
1902 */
1903 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1904 &num_pages);
1905 if (rc == 0)
1906 goto read_complete;
1907
Steve Frenchf19159d2010-04-21 04:12:10 +00001908 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 for (i = 0; i < num_pages; ) {
1910 unsigned contig_pages;
1911 struct page *tmp_page;
1912 unsigned long expected_index;
1913
1914 if (list_empty(page_list))
1915 break;
1916
1917 page = list_entry(page_list->prev, struct page, lru);
1918 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1919
1920 /* count adjacent pages that we will read into */
1921 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001922 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001924 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 if (tmp_page->index == expected_index) {
1926 contig_pages++;
1927 expected_index++;
1928 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001929 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931 if (contig_pages + i > num_pages)
1932 contig_pages = num_pages - i;
1933
1934 /* for reads over a certain size could initiate async
1935 read ahead */
1936
1937 read_size = contig_pages * PAGE_CACHE_SIZE;
1938 /* Read size needs to be in multiples of one page */
1939 read_size = min_t(const unsigned int, read_size,
1940 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001941 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1942 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 rc = -EAGAIN;
1944 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001945 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001946 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 if (rc != 0)
1948 break;
1949 }
1950
Steve Frenchbfa0d752005-08-31 21:50:37 -07001951 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001952 open_file->netfid,
1953 read_size, offset,
1954 &bytes_read, &smb_read_data,
1955 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001956 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001957 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001959 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001960 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001961 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001962 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 smb_read_data = NULL;
1964 }
1965 }
1966 }
1967 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001968 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 break;
1970 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001971 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1973 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1974 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001975 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001978 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001979 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 i++; /* account for partial page */
1981
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001982 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001984 /* BB do we need to verify this common case ?
1985 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 we will hit it on next read */
1987
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001988 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 }
1990 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001991 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001992 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001993 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001994 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 break;
1997 }
1998 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001999 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002000 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002001 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002002 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 smb_read_data = NULL;
2004 }
2005 bytes_read = 0;
2006 }
2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008/* need to free smb_read_data buf before exit */
2009 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002010 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002011 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002012 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002013 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Suresh Jayaraman56698232010-07-05 18:13:25 +05302017read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 FreeXid(xid);
2019 return rc;
2020}
2021
2022static int cifs_readpage_worker(struct file *file, struct page *page,
2023 loff_t *poffset)
2024{
2025 char *read_data;
2026 int rc;
2027
Suresh Jayaraman56698232010-07-05 18:13:25 +05302028 /* Is the page cached? */
2029 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2030 if (rc == 0)
2031 goto read_complete;
2032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 page_cache_get(page);
2034 read_data = kmap(page);
2035 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (rc < 0)
2040 goto io_error;
2041 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002042 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002043
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002044 file->f_path.dentry->d_inode->i_atime =
2045 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 if (PAGE_CACHE_SIZE > rc)
2048 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2049
2050 flush_dcache_page(page);
2051 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302052
2053 /* send this page to the cache */
2054 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2055
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302061
2062read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 return rc;
2064}
2065
2066static int cifs_readpage(struct file *file, struct page *page)
2067{
2068 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2069 int rc = -EACCES;
2070 int xid;
2071
2072 xid = GetXid();
2073
2074 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302075 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302077 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 }
2079
Joe Perchesb6b38f72010-04-21 03:50:45 +00002080 cFYI(1, "readpage %p at offset %d 0x%x\n",
2081 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
2083 rc = cifs_readpage_worker(file, page, &offset);
2084
2085 unlock_page(page);
2086
2087 FreeXid(xid);
2088 return rc;
2089}
2090
Steve Frencha403a0a2007-07-26 15:54:16 +00002091static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2092{
2093 struct cifsFileInfo *open_file;
2094
Jeff Layton44772882010-10-15 15:34:03 -04002095 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002096 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002097 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002098 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002099 return 1;
2100 }
2101 }
Jeff Layton44772882010-10-15 15:34:03 -04002102 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002103 return 0;
2104}
2105
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106/* We do not want to update the file size from server for inodes
2107 open for write - to avoid races with writepage extending
2108 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002109 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 but this is tricky to do without racing with writebehind
2111 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002112bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113{
Steve Frencha403a0a2007-07-26 15:54:16 +00002114 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002115 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002116
Steve Frencha403a0a2007-07-26 15:54:16 +00002117 if (is_inode_writable(cifsInode)) {
2118 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002119 struct cifs_sb_info *cifs_sb;
2120
Steve Frenchc32a0b62006-01-12 14:41:28 -08002121 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002122 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002123 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002124 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002125 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002126 }
2127
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002129 return true;
Steve French7ba52632007-02-08 18:14:13 +00002130
Steve French4b18f2a2008-04-29 00:06:05 +00002131 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002132 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002133 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134}
2135
Nick Piggind9414772008-09-24 11:32:59 -04002136static int cifs_write_begin(struct file *file, struct address_space *mapping,
2137 loff_t pos, unsigned len, unsigned flags,
2138 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139{
Nick Piggind9414772008-09-24 11:32:59 -04002140 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2141 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002142 loff_t page_start = pos & PAGE_MASK;
2143 loff_t i_size;
2144 struct page *page;
2145 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
Joe Perchesb6b38f72010-04-21 03:50:45 +00002147 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002148
Nick Piggin54566b22009-01-04 12:00:53 -08002149 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002150 if (!page) {
2151 rc = -ENOMEM;
2152 goto out;
2153 }
Nick Piggind9414772008-09-24 11:32:59 -04002154
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002155 if (PageUptodate(page))
2156 goto out;
Steve French8a236262007-03-06 00:31:00 +00002157
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002158 /*
2159 * If we write a full page it will be up to date, no need to read from
2160 * the server. If the write is short, we'll end up doing a sync write
2161 * instead.
2162 */
2163 if (len == PAGE_CACHE_SIZE)
2164 goto out;
2165
2166 /*
2167 * optimize away the read when we have an oplock, and we're not
2168 * expecting to use any of the data we'd be reading in. That
2169 * is, when the page lies beyond the EOF, or straddles the EOF
2170 * and the write will cover all of the existing data.
2171 */
2172 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2173 i_size = i_size_read(mapping->host);
2174 if (page_start >= i_size ||
2175 (offset == 0 && (pos + len) >= i_size)) {
2176 zero_user_segments(page, 0, offset,
2177 offset + len,
2178 PAGE_CACHE_SIZE);
2179 /*
2180 * PageChecked means that the parts of the page
2181 * to which we're not writing are considered up
2182 * to date. Once the data is copied to the
2183 * page, it can be set uptodate.
2184 */
2185 SetPageChecked(page);
2186 goto out;
2187 }
2188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Nick Piggind9414772008-09-24 11:32:59 -04002190 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002191 /*
2192 * might as well read a page, it is fast enough. If we get
2193 * an error, we don't need to return it. cifs_write_end will
2194 * do a sync write instead since PG_uptodate isn't set.
2195 */
2196 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002197 } else {
2198 /* we could try using another file handle if there is one -
2199 but how would we lock it to prevent close of that handle
2200 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002201 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002202 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002203out:
2204 *pagep = page;
2205 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206}
2207
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302208static int cifs_release_page(struct page *page, gfp_t gfp)
2209{
2210 if (PagePrivate(page))
2211 return 0;
2212
2213 return cifs_fscache_release_page(page, gfp);
2214}
2215
2216static void cifs_invalidate_page(struct page *page, unsigned long offset)
2217{
2218 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2219
2220 if (offset == 0)
2221 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2222}
2223
Tejun Heo9b646972010-07-20 22:09:02 +02002224void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002225{
2226 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2227 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002228 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002229 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002230 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002231
2232 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002233 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002234 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002235 else
Al Viro8737c932009-12-24 06:47:55 -05002236 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002237 rc = filemap_fdatawrite(inode->i_mapping);
2238 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002239 rc = filemap_fdatawait(inode->i_mapping);
2240 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002241 invalidate_remote_inode(inode);
2242 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002243 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002244 }
2245
2246 /*
2247 * releasing stale oplock after recent reconnect of smb session using
2248 * a now incorrect file handle is not a data integrity issue but do
2249 * not bother sending an oplock release if session to server still is
2250 * disconnected since oplock already released by the server
2251 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002252 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002253 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2254 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002255 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002256 }
Tejun Heo9b646972010-07-20 22:09:02 +02002257
2258 /*
2259 * We might have kicked in before is_valid_oplock_break()
2260 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302261 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002262 */
Jeff Layton44772882010-10-15 15:34:03 -04002263 spin_lock(&cifs_file_list_lock);
2264 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002265
2266 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002267}
2268
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002269/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002270void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002271{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002272 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002273 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002274}
2275
Tejun Heo9b646972010-07-20 22:09:02 +02002276void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002277{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002278 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002279 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002280}
2281
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002282const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 .readpage = cifs_readpage,
2284 .readpages = cifs_readpages,
2285 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002286 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002287 .write_begin = cifs_write_begin,
2288 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302290 .releasepage = cifs_release_page,
2291 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 /* .sync_page = cifs_sync_page, */
2293 /* .direct_IO = */
2294};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002295
2296/*
2297 * cifs_readpages requires the server to support a buffer large enough to
2298 * contain the header plus one complete page of data. Otherwise, we need
2299 * to leave cifs_readpages out of the address space operations.
2300 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002301const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002302 .readpage = cifs_readpage,
2303 .writepage = cifs_writepage,
2304 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002305 .write_begin = cifs_write_begin,
2306 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002307 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302308 .releasepage = cifs_release_page,
2309 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002310 /* .sync_page = cifs_sync_page, */
2311 /* .direct_IO = */
2312};