blob: 8c81e7b14d53d5d347cf0701d5d65ef8cafb328e [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 Laytoncea21802007-11-20 23:19:03 +0000134 if (rc != 0)
Jeff Laytondb460242010-06-16 13:40:17 -0400135 pCifsInode->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000137 cFYI(1, "invalidating remote inode since open detected it "
138 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400139 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 }
141
142client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000143 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400144 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
145 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 else
Jeff Laytondb460242010-06-16 13:40:17 -0400147 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
148 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530150 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000151 pCifsInode->clientCanCacheAll = true;
152 pCifsInode->clientCanCacheRead = true;
Jeff Laytondb460242010-06-16 13:40:17 -0400153 cFYI(1, "Exclusive Oplock granted on inode %p", inode);
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530154 } else if ((oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000155 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 return rc;
158}
159
Jeff Layton608712f2010-10-15 15:33:56 -0400160int cifs_posix_open(char *full_path, struct inode **pinode,
161 struct super_block *sb, int mode, unsigned int f_flags,
162 __u32 *poplock, __u16 *pnetfid, int xid)
163{
164 int rc;
165 FILE_UNIX_BASIC_INFO *presp_data;
166 __u32 posix_flags = 0;
167 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
168 struct cifs_fattr fattr;
169 struct tcon_link *tlink;
170 struct cifsTconInfo *tcon;
171
172 cFYI(1, "posix open %s", full_path);
173
174 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
175 if (presp_data == NULL)
176 return -ENOMEM;
177
178 tlink = cifs_sb_tlink(cifs_sb);
179 if (IS_ERR(tlink)) {
180 rc = PTR_ERR(tlink);
181 goto posix_open_ret;
182 }
183
184 tcon = tlink_tcon(tlink);
185 mode &= ~current_umask();
186
187 posix_flags = cifs_posix_convert_flags(f_flags);
188 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
189 poplock, full_path, cifs_sb->local_nls,
190 cifs_sb->mnt_cifs_flags &
191 CIFS_MOUNT_MAP_SPECIAL_CHR);
192 cifs_put_tlink(tlink);
193
194 if (rc)
195 goto posix_open_ret;
196
197 if (presp_data->Type == cpu_to_le32(-1))
198 goto posix_open_ret; /* open ok, caller does qpathinfo */
199
200 if (!pinode)
201 goto posix_open_ret; /* caller does not need info */
202
203 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
204
205 /* get new inode and set it up */
206 if (*pinode == NULL) {
207 cifs_fill_uniqueid(sb, &fattr);
208 *pinode = cifs_iget(sb, &fattr);
209 if (!*pinode) {
210 rc = -ENOMEM;
211 goto posix_open_ret;
212 }
213 } else {
214 cifs_fattr_to_inode(*pinode, &fattr);
215 }
216
217posix_open_ret:
218 kfree(presp_data);
219 return rc;
220}
221
Jeff Layton15ecb432010-10-15 15:34:02 -0400222struct cifsFileInfo *
223cifs_new_fileinfo(__u16 fileHandle, struct file *file,
224 struct tcon_link *tlink, __u32 oplock)
225{
226 struct dentry *dentry = file->f_path.dentry;
227 struct inode *inode = dentry->d_inode;
228 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
229 struct cifsFileInfo *pCifsFile;
230
231 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
232 if (pCifsFile == NULL)
233 return pCifsFile;
234
235 pCifsFile->netfid = fileHandle;
236 pCifsFile->pid = current->tgid;
237 pCifsFile->uid = current_fsuid();
238 pCifsFile->dentry = dget(dentry);
239 pCifsFile->f_flags = file->f_flags;
240 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400241 pCifsFile->tlink = cifs_get_tlink(tlink);
242 mutex_init(&pCifsFile->fh_mutex);
243 mutex_init(&pCifsFile->lock_mutex);
244 INIT_LIST_HEAD(&pCifsFile->llist);
245 atomic_set(&pCifsFile->count, 1);
246 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
247
Jeff Layton44772882010-10-15 15:34:03 -0400248 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400249 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
250 /* if readable file instance put first in list*/
251 if (file->f_mode & FMODE_READ)
252 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
253 else
254 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400255 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400256
257 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
258 pCifsInode->clientCanCacheAll = true;
259 pCifsInode->clientCanCacheRead = true;
260 cFYI(1, "Exclusive Oplock inode %p", inode);
261 } else if ((oplock & 0xF) == OPLOCK_READ)
262 pCifsInode->clientCanCacheRead = true;
263
264 file->private_data = pCifsFile;
265 return pCifsFile;
266}
267
Steve Frenchcdff08e2010-10-21 22:46:14 +0000268/*
269 * Release a reference on the file private data. This may involve closing
270 * the filehandle out on the server.
271 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400272void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
273{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000274 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
275 struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
276 struct cifsLockInfo *li, *tmp;
277
278 spin_lock(&cifs_file_list_lock);
279 if (!atomic_dec_and_test(&cifs_file->count)) {
280 spin_unlock(&cifs_file_list_lock);
281 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400282 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000283
284 /* remove it from the lists */
285 list_del(&cifs_file->flist);
286 list_del(&cifs_file->tlist);
287
288 if (list_empty(&cifsi->openFileList)) {
289 cFYI(1, "closing last open instance for inode %p",
290 cifs_file->dentry->d_inode);
291 cifsi->clientCanCacheRead = false;
292 cifsi->clientCanCacheAll = false;
293 }
294 spin_unlock(&cifs_file_list_lock);
295
296 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
297 int xid, rc;
298
299 xid = GetXid();
300 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
301 FreeXid(xid);
302 }
303
304 /* Delete any outstanding lock records. We'll lose them when the file
305 * is closed anyway.
306 */
307 mutex_lock(&cifs_file->lock_mutex);
308 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
309 list_del(&li->llist);
310 kfree(li);
311 }
312 mutex_unlock(&cifs_file->lock_mutex);
313
314 cifs_put_tlink(cifs_file->tlink);
315 dput(cifs_file->dentry);
316 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400317}
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319int cifs_open(struct inode *inode, struct file *file)
320{
321 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400322 int xid;
323 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000325 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400326 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400327 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 char *full_path = NULL;
330 int desiredAccess;
331 int disposition;
332 __u16 netfid;
333 FILE_ALL_INFO *buf = NULL;
334
335 xid = GetXid();
336
337 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400338 tlink = cifs_sb_tlink(cifs_sb);
339 if (IS_ERR(tlink)) {
340 FreeXid(xid);
341 return PTR_ERR(tlink);
342 }
343 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Steve Frencha6ce4932009-04-09 01:14:32 +0000345 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800347 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530349 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400350 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
352
Joe Perchesb6b38f72010-04-21 03:50:45 +0000353 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
354 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000355
356 if (oplockEnabled)
357 oplock = REQ_OPLOCK;
358 else
359 oplock = 0;
360
Steve French64cc2c62009-03-04 19:54:08 +0000361 if (!tcon->broken_posix_open && tcon->unix_ext &&
362 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000363 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
364 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000365 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400366 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000367 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400368 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000369 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000370 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400371
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400372 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
373 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400374 if (pCifsFile == NULL) {
375 CIFSSMBClose(xid, tcon, netfid);
376 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400377 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530378
379 cifs_fscache_set_inode_cookie(inode, file);
380
Steve French276a74a2009-03-03 18:00:34 +0000381 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000382 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
383 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000384 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000385 " unexpected error on SMB posix open"
386 ", disabling posix open support."
387 " Check if server update available.",
388 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000389 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000390 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000391 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
392 (rc != -EOPNOTSUPP)) /* path not found or net err */
393 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000394 /* else fallthrough to retry open the old way on network i/o
395 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000396 }
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 desiredAccess = cifs_convert_flags(file->f_flags);
399
400/*********************************************************************
401 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000402 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000404 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 * O_CREAT FILE_OPEN_IF
406 * O_CREAT | O_EXCL FILE_CREATE
407 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
408 * O_TRUNC FILE_OVERWRITE
409 * none of the above FILE_OPEN
410 *
411 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000412 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 * O_CREAT | O_TRUNC is similar but truncates the existing
414 * file rather than creating a new file as FILE_SUPERSEDE does
415 * (which uses the attributes / metadata passed in on open call)
416 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000417 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 *? and the read write flags match reasonably. O_LARGEFILE
419 *? is irrelevant because largefile support is always used
420 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
421 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
422 *********************************************************************/
423
424 disposition = cifs_get_disposition(file->f_flags);
425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 /* BB pass O_SYNC flag through on file attributes .. BB */
427
428 /* Also refresh inode by passing in file_info buf returned by SMBOpen
429 and calling get_inode_info with returned buf (at least helps
430 non-Unix server case) */
431
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000432 /* BB we can not do this if this is the second open of a file
433 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
435 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
436 if (!buf) {
437 rc = -ENOMEM;
438 goto out;
439 }
Steve French5bafd762006-06-07 00:18:43 +0000440
Jeff Laytona6e8a842010-09-20 16:01:33 -0700441 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000442 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000443 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700444 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
445 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000446 else
447 rc = -EIO; /* no NT SMB support fall into legacy open below */
448
Steve Frencha9d02ad2005-08-24 23:06:05 -0700449 if (rc == -EIO) {
450 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000451 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700452 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
453 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
454 & CIFS_MOUNT_MAP_SPECIAL_CHR);
455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000457 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 goto out;
459 }
Jeff Layton3321b792009-09-25 09:53:37 -0400460
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530461 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400462 if (rc != 0)
463 goto out;
464
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400465 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400466 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 rc = -ENOMEM;
468 goto out;
469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530471 cifs_fscache_set_inode_cookie(inode, file);
472
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 /* time to set mode which we can not set earlier due to
475 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000476 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400477 struct cifs_unix_set_info_args args = {
478 .mode = inode->i_mode,
479 .uid = NO_CHANGE_64,
480 .gid = NO_CHANGE_64,
481 .ctime = NO_CHANGE_64,
482 .atime = NO_CHANGE_64,
483 .mtime = NO_CHANGE_64,
484 .device = 0,
485 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400486 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
487 cifs_sb->local_nls,
488 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700489 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 }
491 }
492
493out:
494 kfree(buf);
495 kfree(full_path);
496 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400497 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return rc;
499}
500
Adrian Bunk04187262006-06-30 18:23:04 +0200501/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502/* to server was lost */
503static int cifs_relock_file(struct cifsFileInfo *cifsFile)
504{
505 int rc = 0;
506
507/* BB list all locks open on this file and relock */
508
509 return rc;
510}
511
Jeff Layton15886172010-10-15 15:33:59 -0400512static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400515 int xid;
516 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000518 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000520 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 char *full_path = NULL;
522 int desiredAccess;
523 int disposition = FILE_OPEN;
524 __u16 netfid;
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400527 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000528 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400529 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530530 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530532 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
534
Jeff Layton15886172010-10-15 15:33:59 -0400535 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400537 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/* can not grab rename sem here because various ops, including
540 those that already have the rename sem can end up causing writepage
541 to get called and if the server was down that means we end up here,
542 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400543 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000545 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400546 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000548 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
550
Joe Perchesb6b38f72010-04-21 03:50:45 +0000551 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400552 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 if (oplockEnabled)
555 oplock = REQ_OPLOCK;
556 else
Steve French4b18f2a2008-04-29 00:06:05 +0000557 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Steve French7fc8f4e2009-02-23 20:43:11 +0000559 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
560 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
561 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400562
563 /*
564 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
565 * original open. Must mask them off for a reopen.
566 */
Jeff Layton15886172010-10-15 15:33:59 -0400567 unsigned int oflags = pCifsFile->f_flags &
568 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400569
Jeff Layton2422f672010-06-16 13:40:16 -0400570 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000571 cifs_sb->mnt_file_mode /* ignored */,
572 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000573 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000574 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000575 goto reopen_success;
576 }
577 /* fallthrough to retry open the old way on errors, especially
578 in the reconnect path it is important to retry hard */
579 }
580
Jeff Layton15886172010-10-15 15:33:59 -0400581 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000584 by SMBOpen and then calling get_inode_info with returned buf
585 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 and server version of file size can be stale. If we knew for sure
587 that inode was not dirty locally we could do this */
588
Steve French7fc8f4e2009-02-23 20:43:11 +0000589 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000591 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700592 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400594 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000595 cFYI(1, "cifs_open returned 0x%x", rc);
596 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400597 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
Jeff Layton15886172010-10-15 15:33:59 -0400599
600reopen_success:
601 pCifsFile->netfid = netfid;
602 pCifsFile->invalidHandle = false;
603 mutex_unlock(&pCifsFile->fh_mutex);
604 pCifsInode = CIFS_I(inode);
605
606 if (can_flush) {
607 rc = filemap_write_and_wait(inode->i_mapping);
608 if (rc != 0)
609 CIFS_I(inode)->write_behind_rc = rc;
610
611 pCifsInode->clientCanCacheAll = false;
612 pCifsInode->clientCanCacheRead = false;
613 if (tcon->unix_ext)
614 rc = cifs_get_inode_info_unix(&inode,
615 full_path, inode->i_sb, xid);
616 else
617 rc = cifs_get_inode_info(&inode,
618 full_path, NULL, inode->i_sb,
619 xid, NULL);
620 } /* else we are writing out data to server already
621 and could deadlock if we tried to flush data, and
622 since we do not know if we have data that would
623 invalidate the current end of file on the server
624 we can not go to the server to get the new inod
625 info */
626 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
627 pCifsInode->clientCanCacheAll = true;
628 pCifsInode->clientCanCacheRead = true;
629 cFYI(1, "Exclusive Oplock granted on inode %p",
630 pCifsFile->dentry->d_inode);
631 } else if ((oplock & 0xF) == OPLOCK_READ) {
632 pCifsInode->clientCanCacheRead = true;
633 pCifsInode->clientCanCacheAll = false;
634 } else {
635 pCifsInode->clientCanCacheRead = false;
636 pCifsInode->clientCanCacheAll = false;
637 }
638 cifs_relock_file(pCifsFile);
639
640reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 kfree(full_path);
642 FreeXid(xid);
643 return rc;
644}
645
646int cifs_close(struct inode *inode, struct file *file)
647{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000648 cifsFileInfo_put(file->private_data);
649 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Steve Frenchcdff08e2010-10-21 22:46:14 +0000651 /* return code from the ->release op is always ignored */
652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
655int cifs_closedir(struct inode *inode, struct file *file)
656{
657 int rc = 0;
658 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700659 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 char *ptmp;
661
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 xid = GetXid();
665
666 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400667 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Joe Perchesb6b38f72010-04-21 03:50:45 +0000669 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400670 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000671 if (!pCFileStruct->srch_inf.endOfSearch &&
672 !pCFileStruct->invalidHandle) {
673 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400674 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cFYI(1, "Closing uncompleted readdir with rc %d",
677 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 /* not much we can do if it fails anyway, ignore rc */
679 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000680 } else
Jeff Layton44772882010-10-15 15:34:03 -0400681 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
683 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000684 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000686 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000687 cifs_small_buf_release(ptmp);
688 else
689 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400691 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 kfree(file->private_data);
693 file->private_data = NULL;
694 }
695 /* BB can we lock the filestruct while this is going on? */
696 FreeXid(xid);
697 return rc;
698}
699
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000700static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
701 __u64 offset, __u8 lockType)
702{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000703 struct cifsLockInfo *li =
704 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000705 if (li == NULL)
706 return -ENOMEM;
707 li->offset = offset;
708 li->length = len;
709 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000710 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000711 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000712 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000713 return 0;
714}
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
717{
718 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 __u32 numLock = 0;
720 __u32 numUnlock = 0;
721 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000722 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000724 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000725 __u16 netfid;
726 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000727 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 length = 1 + pfLock->fl_end - pfLock->fl_start;
730 rc = -EACCES;
731 xid = GetXid();
732
Joe Perchesb6b38f72010-04-21 03:50:45 +0000733 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000735 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000736 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000739 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000741 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000743 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000744 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 }
746 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cFYI(1, "Process suspended by mandatory locking - "
748 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000750 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000751 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
755 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000756 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 numLock = 1;
758 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000761 /* Check if unlock includes more than
762 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000764 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 lockType |= LOCKING_ANDX_SHARED_LOCK;
766 numLock = 1;
767 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000768 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 numLock = 1;
770 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000771 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 lockType |= LOCKING_ANDX_SHARED_LOCK;
773 numLock = 1;
774 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000775 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800777 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400778 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530781 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530783 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
Steve French08547b02006-02-28 22:39:25 +0000785 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Steve French13a6e422008-12-02 17:24:33 +0000787 if ((tcon->ses->capabilities & CAP_UNIX) &&
788 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000789 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000790 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000791 /* BB add code here to normalize offset and length to
792 account for negative length which we can not accept over the
793 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000795 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000796 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000797 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000798 posix_lock_type = CIFS_RDLCK;
799 else
800 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000801 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000802 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000803 posix_lock_type, wait_flag);
804 FreeXid(xid);
805 return rc;
806 }
807
808 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000809 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000810 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000812 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 pfLock->fl_start, 1 /* numUnlock */ ,
814 0 /* numLock */ , lockType,
815 0 /* wait flag */ );
816 pfLock->fl_type = F_UNLCK;
817 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000818 cERROR(1, "Error unlocking previously locked "
819 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 rc = 0;
821
822 } else {
823 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400824 rc = 0;
825
826 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
827 pfLock->fl_type = F_WRLCK;
828 } else {
829 rc = CIFSSMBLock(xid, tcon, netfid, length,
830 pfLock->fl_start, 0, 1,
831 lockType | LOCKING_ANDX_SHARED_LOCK,
832 0 /* wait flag */);
833 if (rc == 0) {
834 rc = CIFSSMBLock(xid, tcon, netfid,
835 length, pfLock->fl_start, 1, 0,
836 lockType |
837 LOCKING_ANDX_SHARED_LOCK,
838 0 /* wait flag */);
839 pfLock->fl_type = F_RDLCK;
840 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000841 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400842 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000843 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400844 rc = 0;
845 } else {
846 pfLock->fl_type = F_WRLCK;
847 rc = 0;
848 }
849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851
852 FreeXid(xid);
853 return rc;
854 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000855
856 if (!numLock && !numUnlock) {
857 /* if no lock or unlock then nothing
858 to do since we do not know what it is */
859 FreeXid(xid);
860 return -EOPNOTSUPP;
861 }
862
863 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000864 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000865 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000866 posix_lock_type = CIFS_RDLCK;
867 else
868 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000869
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000870 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000871 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000872
Steve French13a6e422008-12-02 17:24:33 +0000873 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000874 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000875 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000876 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700877 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000878
879 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000880 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000881 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000882 0, numLock, lockType, wait_flag);
883
884 if (rc == 0) {
885 /* For Windows locks we must store them. */
886 rc = store_file_lock(fid, length,
887 pfLock->fl_start, lockType);
888 }
889 } else if (numUnlock) {
890 /* For each stored lock that this unlock overlaps
891 completely, unlock it. */
892 int stored_rc = 0;
893 struct cifsLockInfo *li, *tmp;
894
Steve French6b70c952006-09-21 07:35:29 +0000895 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000896 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000897 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
898 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000899 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000900 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000901 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000903 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000904 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000905 if (stored_rc)
906 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000907 else {
908 list_del(&li->llist);
909 kfree(li);
910 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000911 }
912 }
Roland Dreier796e5662007-05-03 04:33:45 +0000913 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000914 }
915 }
916
Steve Frenchd634cc12005-08-26 14:42:59 -0500917 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 posix_lock_file_wait(file, pfLock);
919 FreeXid(xid);
920 return rc;
921}
922
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400923/*
924 * Set the timeout on write requests past EOF. For some servers (Windows)
925 * these calls can be very long.
926 *
927 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
928 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
929 * The 10M cutoff is totally arbitrary. A better scheme for this would be
930 * welcome if someone wants to suggest one.
931 *
932 * We may be able to do a better job with this if there were some way to
933 * declare that a file should be sparse.
934 */
935static int
936cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
937{
938 if (offset <= cifsi->server_eof)
939 return CIFS_STD_OP;
940 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
941 return CIFS_VLONG_OP;
942 else
943 return CIFS_LONG_OP;
944}
945
946/* update the file size (if needed) after a write */
947static void
948cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
949 unsigned int bytes_written)
950{
951 loff_t end_of_write = offset + bytes_written;
952
953 if (end_of_write > cifsi->server_eof)
954 cifsi->server_eof = end_of_write;
955}
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957ssize_t cifs_user_write(struct file *file, const char __user *write_data,
958 size_t write_size, loff_t *poffset)
959{
960 int rc = 0;
961 unsigned int bytes_written = 0;
962 unsigned int total_written;
963 struct cifs_sb_info *cifs_sb;
964 struct cifsTconInfo *pTcon;
965 int xid, long_op;
966 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400967 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800969 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Joe Perchesb6b38f72010-04-21 03:50:45 +0000971 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
972 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 if (file->private_data == NULL)
975 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700976
Joe Perchesc21dfb62010-07-12 13:50:14 -0700977 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400978 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000979
Jeff Layton838726c2008-08-28 07:54:59 -0400980 rc = generic_write_checks(file, poffset, &write_size, 0);
981 if (rc)
982 return rc;
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400986 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 for (total_written = 0; write_size > total_written;
988 total_written += bytes_written) {
989 rc = -EAGAIN;
990 while (rc == -EAGAIN) {
991 if (file->private_data == NULL) {
992 /* file has been closed on us */
993 FreeXid(xid);
994 /* if we have gotten here we have written some data
995 and blocked, and the file has been freed on us while
996 we blocked so return what we managed to write */
997 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 /* we could deadlock if we called
1001 filemap_fdatawait from here so tell
1002 reopen_file not to flush data to server
1003 now */
Jeff Layton15886172010-10-15 15:33:59 -04001004 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (rc != 0)
1006 break;
1007 }
1008
1009 rc = CIFSSMBWrite(xid, pTcon,
1010 open_file->netfid,
1011 min_t(const int, cifs_sb->wsize,
1012 write_size - total_written),
1013 *poffset, &bytes_written,
1014 NULL, write_data + total_written, long_op);
1015 }
1016 if (rc || (bytes_written == 0)) {
1017 if (total_written)
1018 break;
1019 else {
1020 FreeXid(xid);
1021 return rc;
1022 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001023 } else {
1024 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001026 }
Steve French133672e2007-11-13 22:41:37 +00001027 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 15 seconds is plenty */
1029 }
1030
Steve Frencha4544342005-08-24 13:59:35 -07001031 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001034 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1035 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001036/* Do not update local mtime - server will set its actual value on write
1037 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001038 * current_fs_time(inode->i_sb);*/
1039 if (total_written > 0) {
1040 spin_lock(&inode->i_lock);
1041 if (*poffset > file->f_path.dentry->d_inode->i_size)
1042 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001044 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001046 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 FreeXid(xid);
1049 return total_written;
1050}
1051
Jeff Layton7da4b492010-10-15 15:34:00 -04001052static ssize_t cifs_write(struct cifsFileInfo *open_file,
1053 const char *write_data, size_t write_size,
1054 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
1056 int rc = 0;
1057 unsigned int bytes_written = 0;
1058 unsigned int total_written;
1059 struct cifs_sb_info *cifs_sb;
1060 struct cifsTconInfo *pTcon;
1061 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001062 struct dentry *dentry = open_file->dentry;
1063 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Jeff Layton7da4b492010-10-15 15:34:00 -04001065 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Joe Perchesb6b38f72010-04-21 03:50:45 +00001067 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001068 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Jeff Layton13cfb732010-09-29 19:51:11 -04001070 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001074 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 for (total_written = 0; write_size > total_written;
1076 total_written += bytes_written) {
1077 rc = -EAGAIN;
1078 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 /* we could deadlock if we called
1081 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001082 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001084 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (rc != 0)
1086 break;
1087 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001088 if (experimEnabled || (pTcon->ses->server &&
1089 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001090 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001091 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001092 struct kvec iov[2];
1093 unsigned int len;
1094
Steve French0ae0efa2005-10-10 10:57:19 -07001095 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001096 write_size - total_written);
1097 /* iov[0] is reserved for smb header */
1098 iov[1].iov_base = (char *)write_data +
1099 total_written;
1100 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001101 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001102 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001103 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001104 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001105 } else
Steve French60808232006-04-22 15:53:05 +00001106 rc = CIFSSMBWrite(xid, pTcon,
1107 open_file->netfid,
1108 min_t(const int, cifs_sb->wsize,
1109 write_size - total_written),
1110 *poffset, &bytes_written,
1111 write_data + total_written,
1112 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
1114 if (rc || (bytes_written == 0)) {
1115 if (total_written)
1116 break;
1117 else {
1118 FreeXid(xid);
1119 return rc;
1120 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001121 } else {
1122 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001124 }
Steve French133672e2007-11-13 22:41:37 +00001125 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 15 seconds is plenty */
1127 }
1128
Steve Frencha4544342005-08-24 13:59:35 -07001129 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Jeff Layton7da4b492010-10-15 15:34:00 -04001131 if (total_written > 0) {
1132 spin_lock(&dentry->d_inode->i_lock);
1133 if (*poffset > dentry->d_inode->i_size)
1134 i_size_write(dentry->d_inode, *poffset);
1135 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001137 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 FreeXid(xid);
1139 return total_written;
1140}
1141
Steve French630f3f0c2007-10-25 21:17:17 +00001142#ifdef CONFIG_CIFS_EXPERIMENTAL
Jeff Layton6508d902010-09-29 19:51:11 -04001143struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1144 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001145{
1146 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001147 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1148
1149 /* only filter by fsuid on multiuser mounts */
1150 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1151 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001152
Jeff Layton44772882010-10-15 15:34:03 -04001153 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001154 /* we could simply get the first_list_entry since write-only entries
1155 are always at the end of the list but since the first entry might
1156 have a close pending, we go through the whole list */
1157 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001158 if (fsuid_only && open_file->uid != current_fsuid())
1159 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001160 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001161 if (!open_file->invalidHandle) {
1162 /* found a good file */
1163 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001164 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001165 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001166 return open_file;
1167 } /* else might as well continue, and look for
1168 another, or simply have the caller reopen it
1169 again rather than trying to fix this handle */
1170 } else /* write only file */
1171 break; /* write only files are last so must be done */
1172 }
Jeff Layton44772882010-10-15 15:34:03 -04001173 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001174 return NULL;
1175}
1176#endif
1177
Jeff Layton6508d902010-09-29 19:51:11 -04001178struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1179 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001180{
1181 struct cifsFileInfo *open_file;
Jeff Layton6508d902010-09-29 19:51:11 -04001182 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
Jeff Layton2846d382008-09-22 21:33:33 -04001183 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001184 int rc;
Steve French6148a742005-10-05 12:23:19 -07001185
Steve French60808232006-04-22 15:53:05 +00001186 /* Having a null inode here (because mapping->host was set to zero by
1187 the VFS or MM) should not happen but we had reports of on oops (due to
1188 it being zero) during stress testcases so we need to check for it */
1189
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001190 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001191 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001192 dump_stack();
1193 return NULL;
1194 }
1195
Jeff Layton6508d902010-09-29 19:51:11 -04001196 /* only filter by fsuid on multiuser mounts */
1197 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1198 fsuid_only = false;
1199
Jeff Layton44772882010-10-15 15:34:03 -04001200 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001201refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001202 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001203 if (!any_available && open_file->pid != current->tgid)
1204 continue;
1205 if (fsuid_only && open_file->uid != current_fsuid())
1206 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001207 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001208 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001209
1210 if (!open_file->invalidHandle) {
1211 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001212 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001213 return open_file;
1214 }
Steve French8840dee2007-11-16 23:05:52 +00001215
Jeff Layton44772882010-10-15 15:34:03 -04001216 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001217
Steve French9b22b0b2007-10-02 01:11:08 +00001218 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001219 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001220 if (!rc)
1221 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001222
Steve Frenchcdff08e2010-10-21 22:46:14 +00001223 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001224 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001225 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001226
Steve Frenchcdff08e2010-10-21 22:46:14 +00001227 spin_lock(&cifs_file_list_lock);
1228
Steve French9b22b0b2007-10-02 01:11:08 +00001229 /* else we simply continue to the next entry. Thus
1230 we do not loop on reopen errors. If we
1231 can not reopen the file, for example if we
1232 reconnected to a server with another client
1233 racing to delete or lock the file we would not
1234 make progress if we restarted before the beginning
1235 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001236 }
1237 }
Jeff Layton2846d382008-09-22 21:33:33 -04001238 /* couldn't find useable FH with same pid, try any available */
1239 if (!any_available) {
1240 any_available = true;
1241 goto refind_writable;
1242 }
Jeff Layton44772882010-10-15 15:34:03 -04001243 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001244 return NULL;
1245}
1246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1248{
1249 struct address_space *mapping = page->mapping;
1250 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1251 char *write_data;
1252 int rc = -EFAULT;
1253 int bytes_written = 0;
1254 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001256 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 if (!mapping || !mapping->host)
1259 return -EFAULT;
1260
1261 inode = page->mapping->host;
1262 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 offset += (loff_t)from;
1265 write_data = kmap(page);
1266 write_data += from;
1267
1268 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1269 kunmap(page);
1270 return -EIO;
1271 }
1272
1273 /* racing with truncate? */
1274 if (offset > mapping->host->i_size) {
1275 kunmap(page);
1276 return 0; /* don't care */
1277 }
1278
1279 /* check to make sure that we are not extending the file */
1280 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001281 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Jeff Layton6508d902010-09-29 19:51:11 -04001283 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001284 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001285 bytes_written = cifs_write(open_file, write_data,
1286 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001287 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001289 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001290 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001291 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001292 else if (bytes_written < 0)
1293 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001294 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001295 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 rc = -EIO;
1297 }
1298
1299 kunmap(page);
1300 return rc;
1301}
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001304 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
Steve French37c0eb42005-10-05 14:50:29 -07001306 struct backing_dev_info *bdi = mapping->backing_dev_info;
1307 unsigned int bytes_to_write;
1308 unsigned int bytes_written;
1309 struct cifs_sb_info *cifs_sb;
1310 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001311 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001312 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001313 int range_whole = 0;
1314 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001315 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001316 int n_iov = 0;
1317 pgoff_t next;
1318 int nr_pages;
1319 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001320 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001321 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001322 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001323 struct page *page;
1324 struct pagevec pvec;
1325 int rc = 0;
1326 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001327 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Jeff Laytonf3983c22010-09-22 16:17:40 -07001329 /*
1330 * BB: Is this meaningful for a non-block-device file system?
1331 * If it is, we should test it again after we do I/O
1332 */
1333 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1334 wbc->encountered_congestion = 1;
1335 return 0;
1336 }
1337
Steve French37c0eb42005-10-05 14:50:29 -07001338 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001339
Steve French37c0eb42005-10-05 14:50:29 -07001340 /*
1341 * If wsize is smaller that the page cache size, default to writing
1342 * one page at a time via cifs_writepage
1343 */
1344 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1345 return generic_writepages(mapping, wbc);
1346
Steve French9a0c8232007-02-02 04:21:57 +00001347 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001348 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001349 return generic_writepages(mapping, wbc);
1350
Steve French37c0eb42005-10-05 14:50:29 -07001351 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001352 * if there's no open file, then this is likely to fail too,
1353 * but it'll at least handle the return. Maybe it should be
1354 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001355 */
Jeff Layton6508d902010-09-29 19:51:11 -04001356 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001357 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001358 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001359 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001360 }
1361
Jeff Layton13cfb732010-09-29 19:51:11 -04001362 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001363 if (!experimEnabled && tcon->ses->server->secMode &
1364 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1365 cifsFileInfo_put(open_file);
1366 return generic_writepages(mapping, wbc);
1367 }
1368 cifsFileInfo_put(open_file);
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 xid = GetXid();
1371
Steve French37c0eb42005-10-05 14:50:29 -07001372 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001373 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001374 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001375 end = -1;
1376 } else {
1377 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1378 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1379 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1380 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001381 scanned = 1;
1382 }
1383retry:
1384 while (!done && (index <= end) &&
1385 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1386 PAGECACHE_TAG_DIRTY,
1387 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1388 int first;
1389 unsigned int i;
1390
Steve French37c0eb42005-10-05 14:50:29 -07001391 first = -1;
1392 next = 0;
1393 n_iov = 0;
1394 bytes_to_write = 0;
1395
1396 for (i = 0; i < nr_pages; i++) {
1397 page = pvec.pages[i];
1398 /*
1399 * At this point we hold neither mapping->tree_lock nor
1400 * lock on the page itself: the page may be truncated or
1401 * invalidated (changing page->mapping to NULL), or even
1402 * swizzled back from swapper_space to tmpfs file
1403 * mapping
1404 */
1405
1406 if (first < 0)
1407 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001408 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001409 break;
1410
1411 if (unlikely(page->mapping != mapping)) {
1412 unlock_page(page);
1413 break;
1414 }
1415
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001416 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001417 done = 1;
1418 unlock_page(page);
1419 break;
1420 }
1421
1422 if (next && (page->index != next)) {
1423 /* Not next consecutive page */
1424 unlock_page(page);
1425 break;
1426 }
1427
1428 if (wbc->sync_mode != WB_SYNC_NONE)
1429 wait_on_page_writeback(page);
1430
1431 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001432 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001433 unlock_page(page);
1434 break;
1435 }
Steve French84d2f072005-10-12 15:32:05 -07001436
Linus Torvaldscb876f42006-12-23 16:19:07 -08001437 /*
1438 * This actually clears the dirty bit in the radix tree.
1439 * See cifs_writepage() for more commentary.
1440 */
1441 set_page_writeback(page);
1442
Steve French84d2f072005-10-12 15:32:05 -07001443 if (page_offset(page) >= mapping->host->i_size) {
1444 done = 1;
1445 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001446 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001447 break;
1448 }
1449
Steve French37c0eb42005-10-05 14:50:29 -07001450 /*
1451 * BB can we get rid of this? pages are held by pvec
1452 */
1453 page_cache_get(page);
1454
Steve French84d2f072005-10-12 15:32:05 -07001455 len = min(mapping->host->i_size - page_offset(page),
1456 (loff_t)PAGE_CACHE_SIZE);
1457
Steve French37c0eb42005-10-05 14:50:29 -07001458 /* reserve iov[0] for the smb header */
1459 n_iov++;
1460 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001461 iov[n_iov].iov_len = len;
1462 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001463
1464 if (first < 0) {
1465 first = i;
1466 offset = page_offset(page);
1467 }
1468 next = page->index + 1;
1469 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1470 break;
1471 }
1472 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001473 open_file = find_writable_file(CIFS_I(mapping->host),
1474 false);
Steve French23e7dd72005-10-20 13:44:56 -07001475 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001476 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001477 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001478 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001479 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001480 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001481 bytes_to_write, offset,
1482 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001483 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001484 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001485 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001486 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001487
1488 if (rc || bytes_written < bytes_to_write) {
1489 cERROR(1, "Write2 ret %d, wrote %d",
1490 rc, bytes_written);
1491 /* BB what if continued retry is
1492 requested via mount flags? */
1493 if (rc == -ENOSPC)
1494 set_bit(AS_ENOSPC, &mapping->flags);
1495 else
1496 set_bit(AS_EIO, &mapping->flags);
1497 } else {
1498 cifs_stats_bytes_written(tcon, bytes_written);
1499 }
1500
Steve French37c0eb42005-10-05 14:50:29 -07001501 for (i = 0; i < n_iov; i++) {
1502 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001503 /* Should we also set page error on
1504 success rc but too little data written? */
1505 /* BB investigate retry logic on temporary
1506 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001507 when page marked as error */
1508 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001509 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001510 kunmap(page);
1511 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001512 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001513 page_cache_release(page);
1514 }
1515 if ((wbc->nr_to_write -= n_iov) <= 0)
1516 done = 1;
1517 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001518 } else
1519 /* Need to re-find the pages we skipped */
1520 index = pvec.pages[0]->index + 1;
1521
Steve French37c0eb42005-10-05 14:50:29 -07001522 pagevec_release(&pvec);
1523 }
1524 if (!scanned && !done) {
1525 /*
1526 * We hit the last page and there is more work to be done: wrap
1527 * back to the start of the file
1528 */
1529 scanned = 1;
1530 index = 0;
1531 goto retry;
1532 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001533 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001534 mapping->writeback_index = index;
1535
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001537 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 return rc;
1539}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001541static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542{
1543 int rc = -EFAULT;
1544 int xid;
1545
1546 xid = GetXid();
1547/* BB add check for wbc flags */
1548 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001549 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001550 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001551
1552 /*
1553 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1554 *
1555 * A writepage() implementation always needs to do either this,
1556 * or re-dirty the page with "redirty_page_for_writepage()" in
1557 * the case of a failure.
1558 *
1559 * Just unlocking the page will cause the radix tree tag-bits
1560 * to fail to update with the state of the page correctly.
1561 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001562 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1564 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1565 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001566 end_page_writeback(page);
1567 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 FreeXid(xid);
1569 return rc;
1570}
1571
Nick Piggind9414772008-09-24 11:32:59 -04001572static int cifs_write_end(struct file *file, struct address_space *mapping,
1573 loff_t pos, unsigned len, unsigned copied,
1574 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575{
Nick Piggind9414772008-09-24 11:32:59 -04001576 int rc;
1577 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Joe Perchesb6b38f72010-04-21 03:50:45 +00001579 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1580 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001581
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001582 if (PageChecked(page)) {
1583 if (copied == len)
1584 SetPageUptodate(page);
1585 ClearPageChecked(page);
1586 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001587 SetPageUptodate(page);
1588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001590 char *page_data;
1591 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1592 int xid;
1593
1594 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 /* this is probably better than directly calling
1596 partialpage_write since in this function the file handle is
1597 known which we might as well leverage */
1598 /* BB check if anything else missing out of ppw
1599 such as updating last write time */
1600 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001601 rc = cifs_write(file->private_data, page_data + offset,
1602 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001603 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001605
1606 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001607 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001608 rc = copied;
1609 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 set_page_dirty(page);
1611 }
1612
Nick Piggind9414772008-09-24 11:32:59 -04001613 if (rc > 0) {
1614 spin_lock(&inode->i_lock);
1615 if (pos > inode->i_size)
1616 i_size_write(inode, pos);
1617 spin_unlock(&inode->i_lock);
1618 }
1619
1620 unlock_page(page);
1621 page_cache_release(page);
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return rc;
1624}
1625
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001626int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627{
1628 int xid;
1629 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001630 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001631 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001632 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 xid = GetXid();
1635
Joe Perchesb6b38f72010-04-21 03:50:45 +00001636 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001637 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001638
Jeff Laytoncea21802007-11-20 23:19:03 +00001639 rc = filemap_write_and_wait(inode->i_mapping);
1640 if (rc == 0) {
1641 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 CIFS_I(inode)->write_behind_rc = 0;
Jeff Layton13cfb732010-09-29 19:51:11 -04001643 tcon = tlink_tcon(smbfile->tlink);
Steve Frenchbe652442009-02-23 15:21:59 +00001644 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001645 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001646 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001647 }
Steve Frenchb298f222009-02-21 21:17:43 +00001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 FreeXid(xid);
1650 return rc;
1651}
1652
NeilBrown3978d7172006-03-26 01:37:17 -08001653/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654{
1655 struct address_space *mapping;
1656 struct inode *inode;
1657 unsigned long index = page->index;
1658 unsigned int rpages = 0;
1659 int rc = 0;
1660
Steve Frenchf19159d2010-04-21 04:12:10 +00001661 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 mapping = page->mapping;
1663 if (!mapping)
1664 return 0;
1665 inode = mapping->host;
1666 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001667 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001669/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1671
Joe Perchesb6b38f72010-04-21 03:50:45 +00001672/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
NeilBrown3978d7172006-03-26 01:37:17 -08001674#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 if (rc < 0)
1676 return rc;
1677 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001678#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679} */
1680
1681/*
1682 * As file closes, flush all cached write data for this inode checking
1683 * for write behind errors.
1684 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001685int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001687 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 int rc = 0;
1689
1690 /* Rather than do the steps manually:
1691 lock the inode for writing
1692 loop through pages looking for write behind data (dirty pages)
1693 coalesce into contiguous 16K (or smaller) chunks to write to server
1694 send to server (prefer in parallel)
1695 deal with writebehind errors
1696 unlock inode for writing
1697 filemapfdatawrite appears easier for the time being */
1698
1699 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001700 /* reset wb rc if we were able to write out dirty pages */
1701 if (!rc) {
1702 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001704 }
Steve French50c2f752007-07-13 00:33:32 +00001705
Joe Perchesb6b38f72010-04-21 03:50:45 +00001706 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 return rc;
1709}
1710
1711ssize_t cifs_user_read(struct file *file, char __user *read_data,
1712 size_t read_size, loff_t *poffset)
1713{
1714 int rc = -EACCES;
1715 unsigned int bytes_read = 0;
1716 unsigned int total_read = 0;
1717 unsigned int current_read_size;
1718 struct cifs_sb_info *cifs_sb;
1719 struct cifsTconInfo *pTcon;
1720 int xid;
1721 struct cifsFileInfo *open_file;
1722 char *smb_read_data;
1723 char __user *current_offset;
1724 struct smb_com_read_rsp *pSMBr;
1725
1726 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001727 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301730 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301732 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001734 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001735 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
Steve Frenchad7a2922008-02-07 23:25:02 +00001737 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001738 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 for (total_read = 0, current_offset = read_data;
1741 read_size > total_read;
1742 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001743 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 cifs_sb->rsize);
1745 rc = -EAGAIN;
1746 smb_read_data = NULL;
1747 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001748 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001749 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001750 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 if (rc != 0)
1752 break;
1753 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001754 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001755 open_file->netfid,
1756 current_read_size, *poffset,
1757 &bytes_read, &smb_read_data,
1758 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001761 if (copy_to_user(current_offset,
1762 smb_read_data +
1763 4 /* RFC1001 length field */ +
1764 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001765 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001766 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001767
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001769 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001770 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001771 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 smb_read_data = NULL;
1773 }
1774 }
1775 if (rc || (bytes_read == 0)) {
1776 if (total_read) {
1777 break;
1778 } else {
1779 FreeXid(xid);
1780 return rc;
1781 }
1782 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001783 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 *poffset += bytes_read;
1785 }
1786 }
1787 FreeXid(xid);
1788 return total_read;
1789}
1790
1791
1792static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1793 loff_t *poffset)
1794{
1795 int rc = -EACCES;
1796 unsigned int bytes_read = 0;
1797 unsigned int total_read;
1798 unsigned int current_read_size;
1799 struct cifs_sb_info *cifs_sb;
1800 struct cifsTconInfo *pTcon;
1801 int xid;
1802 char *current_offset;
1803 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001804 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
1806 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001807 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301810 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301812 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001814 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001815 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
1817 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001818 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001820 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 read_size > total_read;
1822 total_read += bytes_read, current_offset += bytes_read) {
1823 current_read_size = min_t(const int, read_size - total_read,
1824 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001825 /* For windows me and 9x we do not want to request more
1826 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001827 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001828 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1829 current_read_size = min_t(const int, current_read_size,
1830 pTcon->ses->server->maxBuf - 128);
1831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 rc = -EAGAIN;
1833 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001834 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001835 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (rc != 0)
1837 break;
1838 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001839 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001840 open_file->netfid,
1841 current_read_size, *poffset,
1842 &bytes_read, &current_offset,
1843 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 }
1845 if (rc || (bytes_read == 0)) {
1846 if (total_read) {
1847 break;
1848 } else {
1849 FreeXid(xid);
1850 return rc;
1851 }
1852 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001853 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 *poffset += bytes_read;
1855 }
1856 }
1857 FreeXid(xid);
1858 return total_read;
1859}
1860
1861int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1862{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 int rc, xid;
1864
1865 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001866 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001868 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 FreeXid(xid);
1870 return rc;
1871 }
1872 rc = generic_file_mmap(file, vma);
1873 FreeXid(xid);
1874 return rc;
1875}
1876
1877
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001878static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001879 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880{
1881 struct page *page;
1882 char *target;
1883
1884 while (bytes_read > 0) {
1885 if (list_empty(pages))
1886 break;
1887
1888 page = list_entry(pages->prev, struct page, lru);
1889 list_del(&page->lru);
1890
Nick Piggin315e9952010-04-21 03:18:28 +00001891 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 GFP_KERNEL)) {
1893 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001894 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001895 data += PAGE_CACHE_SIZE;
1896 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 continue;
1898 }
Jeff Layton06b43672010-06-01 10:54:45 -04001899 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001901 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 if (PAGE_CACHE_SIZE > bytes_read) {
1904 memcpy(target, data, bytes_read);
1905 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001906 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 PAGE_CACHE_SIZE - bytes_read);
1908 bytes_read = 0;
1909 } else {
1910 memcpy(target, data, PAGE_CACHE_SIZE);
1911 bytes_read -= PAGE_CACHE_SIZE;
1912 }
1913 kunmap_atomic(target, KM_USER0);
1914
1915 flush_dcache_page(page);
1916 SetPageUptodate(page);
1917 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301919
1920 /* add page to FS-Cache */
1921 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923 return;
1924}
1925
1926static int cifs_readpages(struct file *file, struct address_space *mapping,
1927 struct list_head *page_list, unsigned num_pages)
1928{
1929 int rc = -EACCES;
1930 int xid;
1931 loff_t offset;
1932 struct page *page;
1933 struct cifs_sb_info *cifs_sb;
1934 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001935 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001936 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 char *smb_read_data = NULL;
1938 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001940 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
1942 xid = GetXid();
1943 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301944 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301946 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001948 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001949 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001950 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001951
Suresh Jayaraman56698232010-07-05 18:13:25 +05301952 /*
1953 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1954 * immediately if the cookie is negative
1955 */
1956 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1957 &num_pages);
1958 if (rc == 0)
1959 goto read_complete;
1960
Steve Frenchf19159d2010-04-21 04:12:10 +00001961 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 for (i = 0; i < num_pages; ) {
1963 unsigned contig_pages;
1964 struct page *tmp_page;
1965 unsigned long expected_index;
1966
1967 if (list_empty(page_list))
1968 break;
1969
1970 page = list_entry(page_list->prev, struct page, lru);
1971 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1972
1973 /* count adjacent pages that we will read into */
1974 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001975 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001977 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 if (tmp_page->index == expected_index) {
1979 contig_pages++;
1980 expected_index++;
1981 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 }
1984 if (contig_pages + i > num_pages)
1985 contig_pages = num_pages - i;
1986
1987 /* for reads over a certain size could initiate async
1988 read ahead */
1989
1990 read_size = contig_pages * PAGE_CACHE_SIZE;
1991 /* Read size needs to be in multiples of one page */
1992 read_size = min_t(const unsigned int, read_size,
1993 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001994 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1995 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 rc = -EAGAIN;
1997 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001998 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001999 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 if (rc != 0)
2001 break;
2002 }
2003
Steve Frenchbfa0d752005-08-31 21:50:37 -07002004 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002005 open_file->netfid,
2006 read_size, offset,
2007 &bytes_read, &smb_read_data,
2008 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002009 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002010 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002012 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002013 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002014 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002015 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 smb_read_data = NULL;
2017 }
2018 }
2019 }
2020 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002021 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 break;
2023 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002024 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2026 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2027 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002028 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002031 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002032 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 i++; /* account for partial page */
2034
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002035 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037 /* BB do we need to verify this common case ?
2038 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 we will hit it on next read */
2040
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002041 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002044 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002045 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002046 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 break;
2050 }
2051 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002053 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002055 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 smb_read_data = NULL;
2057 }
2058 bytes_read = 0;
2059 }
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061/* need to free smb_read_data buf before exit */
2062 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002063 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002064 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002065 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002066 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Suresh Jayaraman56698232010-07-05 18:13:25 +05302070read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 FreeXid(xid);
2072 return rc;
2073}
2074
2075static int cifs_readpage_worker(struct file *file, struct page *page,
2076 loff_t *poffset)
2077{
2078 char *read_data;
2079 int rc;
2080
Suresh Jayaraman56698232010-07-05 18:13:25 +05302081 /* Is the page cached? */
2082 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2083 if (rc == 0)
2084 goto read_complete;
2085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 page_cache_get(page);
2087 read_data = kmap(page);
2088 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002091
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 if (rc < 0)
2093 goto io_error;
2094 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002095 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002096
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002097 file->f_path.dentry->d_inode->i_atime =
2098 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002099
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 if (PAGE_CACHE_SIZE > rc)
2101 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2102
2103 flush_dcache_page(page);
2104 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302105
2106 /* send this page to the cache */
2107 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002112 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302114
2115read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 return rc;
2117}
2118
2119static int cifs_readpage(struct file *file, struct page *page)
2120{
2121 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2122 int rc = -EACCES;
2123 int xid;
2124
2125 xid = GetXid();
2126
2127 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302128 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302130 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 }
2132
Joe Perchesb6b38f72010-04-21 03:50:45 +00002133 cFYI(1, "readpage %p at offset %d 0x%x\n",
2134 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 rc = cifs_readpage_worker(file, page, &offset);
2137
2138 unlock_page(page);
2139
2140 FreeXid(xid);
2141 return rc;
2142}
2143
Steve Frencha403a0a2007-07-26 15:54:16 +00002144static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2145{
2146 struct cifsFileInfo *open_file;
2147
Jeff Layton44772882010-10-15 15:34:03 -04002148 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002149 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002150 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002151 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002152 return 1;
2153 }
2154 }
Jeff Layton44772882010-10-15 15:34:03 -04002155 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002156 return 0;
2157}
2158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159/* We do not want to update the file size from server for inodes
2160 open for write - to avoid races with writepage extending
2161 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002162 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 but this is tricky to do without racing with writebehind
2164 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002165bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166{
Steve Frencha403a0a2007-07-26 15:54:16 +00002167 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002168 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002169
Steve Frencha403a0a2007-07-26 15:54:16 +00002170 if (is_inode_writable(cifsInode)) {
2171 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002172 struct cifs_sb_info *cifs_sb;
2173
Steve Frenchc32a0b62006-01-12 14:41:28 -08002174 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002175 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002176 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002177 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002178 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002179 }
2180
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002181 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002182 return true;
Steve French7ba52632007-02-08 18:14:13 +00002183
Steve French4b18f2a2008-04-29 00:06:05 +00002184 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002185 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002186 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187}
2188
Nick Piggind9414772008-09-24 11:32:59 -04002189static int cifs_write_begin(struct file *file, struct address_space *mapping,
2190 loff_t pos, unsigned len, unsigned flags,
2191 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
Nick Piggind9414772008-09-24 11:32:59 -04002193 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2194 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002195 loff_t page_start = pos & PAGE_MASK;
2196 loff_t i_size;
2197 struct page *page;
2198 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Joe Perchesb6b38f72010-04-21 03:50:45 +00002200 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002201
Nick Piggin54566b22009-01-04 12:00:53 -08002202 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002203 if (!page) {
2204 rc = -ENOMEM;
2205 goto out;
2206 }
Nick Piggind9414772008-09-24 11:32:59 -04002207
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002208 if (PageUptodate(page))
2209 goto out;
Steve French8a236262007-03-06 00:31:00 +00002210
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002211 /*
2212 * If we write a full page it will be up to date, no need to read from
2213 * the server. If the write is short, we'll end up doing a sync write
2214 * instead.
2215 */
2216 if (len == PAGE_CACHE_SIZE)
2217 goto out;
2218
2219 /*
2220 * optimize away the read when we have an oplock, and we're not
2221 * expecting to use any of the data we'd be reading in. That
2222 * is, when the page lies beyond the EOF, or straddles the EOF
2223 * and the write will cover all of the existing data.
2224 */
2225 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2226 i_size = i_size_read(mapping->host);
2227 if (page_start >= i_size ||
2228 (offset == 0 && (pos + len) >= i_size)) {
2229 zero_user_segments(page, 0, offset,
2230 offset + len,
2231 PAGE_CACHE_SIZE);
2232 /*
2233 * PageChecked means that the parts of the page
2234 * to which we're not writing are considered up
2235 * to date. Once the data is copied to the
2236 * page, it can be set uptodate.
2237 */
2238 SetPageChecked(page);
2239 goto out;
2240 }
2241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Nick Piggind9414772008-09-24 11:32:59 -04002243 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002244 /*
2245 * might as well read a page, it is fast enough. If we get
2246 * an error, we don't need to return it. cifs_write_end will
2247 * do a sync write instead since PG_uptodate isn't set.
2248 */
2249 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002250 } else {
2251 /* we could try using another file handle if there is one -
2252 but how would we lock it to prevent close of that handle
2253 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002254 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002255 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002256out:
2257 *pagep = page;
2258 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259}
2260
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302261static int cifs_release_page(struct page *page, gfp_t gfp)
2262{
2263 if (PagePrivate(page))
2264 return 0;
2265
2266 return cifs_fscache_release_page(page, gfp);
2267}
2268
2269static void cifs_invalidate_page(struct page *page, unsigned long offset)
2270{
2271 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2272
2273 if (offset == 0)
2274 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2275}
2276
Tejun Heo9b646972010-07-20 22:09:02 +02002277void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002278{
2279 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2280 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002281 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002282 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002283 int rc, waitrc = 0;
2284
2285 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002286 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002287 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002288 else
Al Viro8737c932009-12-24 06:47:55 -05002289 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002290 rc = filemap_fdatawrite(inode->i_mapping);
2291 if (cinode->clientCanCacheRead == 0) {
2292 waitrc = filemap_fdatawait(inode->i_mapping);
2293 invalidate_remote_inode(inode);
2294 }
2295 if (!rc)
2296 rc = waitrc;
2297 if (rc)
2298 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002299 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002300 }
2301
2302 /*
2303 * releasing stale oplock after recent reconnect of smb session using
2304 * a now incorrect file handle is not a data integrity issue but do
2305 * not bother sending an oplock release if session to server still is
2306 * disconnected since oplock already released by the server
2307 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002308 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002309 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2310 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002311 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002312 }
Tejun Heo9b646972010-07-20 22:09:02 +02002313
2314 /*
2315 * We might have kicked in before is_valid_oplock_break()
2316 * finished grabbing reference for us. Make sure it's done by
2317 * waiting for GlobalSMSSeslock.
2318 */
Jeff Layton44772882010-10-15 15:34:03 -04002319 spin_lock(&cifs_file_list_lock);
2320 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002321
2322 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002323}
2324
Tejun Heo9b646972010-07-20 22:09:02 +02002325void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002326{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002327 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002328 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002329}
2330
Tejun Heo9b646972010-07-20 22:09:02 +02002331void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002332{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002333 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002334 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002335}
2336
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002337const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 .readpage = cifs_readpage,
2339 .readpages = cifs_readpages,
2340 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002341 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002342 .write_begin = cifs_write_begin,
2343 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302345 .releasepage = cifs_release_page,
2346 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 /* .sync_page = cifs_sync_page, */
2348 /* .direct_IO = */
2349};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002350
2351/*
2352 * cifs_readpages requires the server to support a buffer large enough to
2353 * contain the header plus one complete page of data. Otherwise, we need
2354 * to leave cifs_readpages out of the address space operations.
2355 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002356const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002357 .readpage = cifs_readpage,
2358 .writepage = cifs_writepage,
2359 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002360 .write_begin = cifs_write_begin,
2361 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002362 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302363 .releasepage = cifs_release_page,
2364 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002365 /* .sync_page = cifs_sync_page, */
2366 /* .direct_IO = */
2367};