blob: 5a28660ca2b5e619955c05d74d9d84b95a994a4b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
Steve Frenchf19159d2010-04-21 04:12:10 +00006 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include "cifsfs.h"
37#include "cifspdu.h"
38#include "cifsglob.h"
39#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42#include "cifs_fs_sb.h"
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +053043#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static inline int cifs_convert_flags(unsigned int flags)
46{
47 if ((flags & O_ACCMODE) == O_RDONLY)
48 return GENERIC_READ;
49 else if ((flags & O_ACCMODE) == O_WRONLY)
50 return GENERIC_WRITE;
51 else if ((flags & O_ACCMODE) == O_RDWR) {
52 /* GENERIC_ALL is too much permission to request
53 can cause unnecessary access denied on create */
54 /* return GENERIC_ALL; */
55 return (GENERIC_READ | GENERIC_WRITE);
56 }
57
Jeff Laytone10f7b52008-05-14 10:21:33 -070058 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
59 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
60 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000061}
Jeff Laytone10f7b52008-05-14 10:21:33 -070062
Jeff Layton608712f2010-10-15 15:33:56 -040063static u32 cifs_posix_convert_flags(unsigned int flags)
Steve French7fc8f4e2009-02-23 20:43:11 +000064{
Jeff Layton608712f2010-10-15 15:33:56 -040065 u32 posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070066
Steve French7fc8f4e2009-02-23 20:43:11 +000067 if ((flags & O_ACCMODE) == O_RDONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040068 posix_flags = SMB_O_RDONLY;
Steve French7fc8f4e2009-02-23 20:43:11 +000069 else if ((flags & O_ACCMODE) == O_WRONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040070 posix_flags = SMB_O_WRONLY;
71 else if ((flags & O_ACCMODE) == O_RDWR)
72 posix_flags = SMB_O_RDWR;
73
74 if (flags & O_CREAT)
75 posix_flags |= SMB_O_CREAT;
76 if (flags & O_EXCL)
77 posix_flags |= SMB_O_EXCL;
78 if (flags & O_TRUNC)
79 posix_flags |= SMB_O_TRUNC;
80 /* be safe and imply O_SYNC for O_DSYNC */
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010081 if (flags & O_DSYNC)
Jeff Layton608712f2010-10-15 15:33:56 -040082 posix_flags |= SMB_O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000083 if (flags & O_DIRECTORY)
Jeff Layton608712f2010-10-15 15:33:56 -040084 posix_flags |= SMB_O_DIRECTORY;
Steve French7fc8f4e2009-02-23 20:43:11 +000085 if (flags & O_NOFOLLOW)
Jeff Layton608712f2010-10-15 15:33:56 -040086 posix_flags |= SMB_O_NOFOLLOW;
Steve French7fc8f4e2009-02-23 20:43:11 +000087 if (flags & O_DIRECT)
Jeff Layton608712f2010-10-15 15:33:56 -040088 posix_flags |= SMB_O_DIRECT;
Steve French7fc8f4e2009-02-23 20:43:11 +000089
90 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091}
92
93static inline int cifs_get_disposition(unsigned int flags)
94{
95 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
96 return FILE_CREATE;
97 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
98 return FILE_OVERWRITE_IF;
99 else if ((flags & O_CREAT) == O_CREAT)
100 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000101 else if ((flags & O_TRUNC) == O_TRUNC)
102 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 else
104 return FILE_OPEN;
105}
106
Jeff Laytondb460242010-06-16 13:40:17 -0400107static inline int cifs_open_inode_helper(struct inode *inode,
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530108 struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 char *full_path, int xid)
110{
Jeff Laytondb460242010-06-16 13:40:17 -0400111 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 struct timespec temp;
113 int rc;
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (pCifsInode->clientCanCacheRead) {
116 /* we have the inode open somewhere else
117 no need to discard cache data */
118 goto client_can_cache;
119 }
120
121 /* BB need same check in cifs_create too? */
122 /* if not oplocked, invalidate inode pages if mtime or file
123 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400124 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Jeff Laytondb460242010-06-16 13:40:17 -0400125 if (timespec_equal(&inode->i_mtime, &temp) &&
126 (inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000128 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 } else {
Jeff Laytondb460242010-06-16 13:40:17 -0400130 if (inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000131 /* BB no need to lock inode until after invalidate
132 since namei code should already have it locked? */
Jeff Laytondb460242010-06-16 13:40:17 -0400133 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400134 mapping_set_error(inode->i_mapping, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000136 cFYI(1, "invalidating remote inode since open detected it "
137 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400138 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140
141client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000142 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400143 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
144 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 else
Jeff Laytondb460242010-06-16 13:40:17 -0400146 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
147 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300149 cifs_set_oplock_level(pCifsInode, oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 return rc;
152}
153
Jeff Layton608712f2010-10-15 15:33:56 -0400154int cifs_posix_open(char *full_path, struct inode **pinode,
155 struct super_block *sb, int mode, unsigned int f_flags,
156 __u32 *poplock, __u16 *pnetfid, int xid)
157{
158 int rc;
159 FILE_UNIX_BASIC_INFO *presp_data;
160 __u32 posix_flags = 0;
161 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
162 struct cifs_fattr fattr;
163 struct tcon_link *tlink;
164 struct cifsTconInfo *tcon;
165
166 cFYI(1, "posix open %s", full_path);
167
168 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
169 if (presp_data == NULL)
170 return -ENOMEM;
171
172 tlink = cifs_sb_tlink(cifs_sb);
173 if (IS_ERR(tlink)) {
174 rc = PTR_ERR(tlink);
175 goto posix_open_ret;
176 }
177
178 tcon = tlink_tcon(tlink);
179 mode &= ~current_umask();
180
181 posix_flags = cifs_posix_convert_flags(f_flags);
182 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
183 poplock, full_path, cifs_sb->local_nls,
184 cifs_sb->mnt_cifs_flags &
185 CIFS_MOUNT_MAP_SPECIAL_CHR);
186 cifs_put_tlink(tlink);
187
188 if (rc)
189 goto posix_open_ret;
190
191 if (presp_data->Type == cpu_to_le32(-1))
192 goto posix_open_ret; /* open ok, caller does qpathinfo */
193
194 if (!pinode)
195 goto posix_open_ret; /* caller does not need info */
196
197 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
198
199 /* get new inode and set it up */
200 if (*pinode == NULL) {
201 cifs_fill_uniqueid(sb, &fattr);
202 *pinode = cifs_iget(sb, &fattr);
203 if (!*pinode) {
204 rc = -ENOMEM;
205 goto posix_open_ret;
206 }
207 } else {
208 cifs_fattr_to_inode(*pinode, &fattr);
209 }
210
211posix_open_ret:
212 kfree(presp_data);
213 return rc;
214}
215
Jeff Layton15ecb432010-10-15 15:34:02 -0400216struct cifsFileInfo *
217cifs_new_fileinfo(__u16 fileHandle, struct file *file,
218 struct tcon_link *tlink, __u32 oplock)
219{
220 struct dentry *dentry = file->f_path.dentry;
221 struct inode *inode = dentry->d_inode;
222 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
223 struct cifsFileInfo *pCifsFile;
224
225 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
226 if (pCifsFile == NULL)
227 return pCifsFile;
228
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400229 pCifsFile->count = 1;
Jeff Layton15ecb432010-10-15 15:34:02 -0400230 pCifsFile->netfid = fileHandle;
231 pCifsFile->pid = current->tgid;
232 pCifsFile->uid = current_fsuid();
233 pCifsFile->dentry = dget(dentry);
234 pCifsFile->f_flags = file->f_flags;
235 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400236 pCifsFile->tlink = cifs_get_tlink(tlink);
237 mutex_init(&pCifsFile->fh_mutex);
238 mutex_init(&pCifsFile->lock_mutex);
239 INIT_LIST_HEAD(&pCifsFile->llist);
Jeff Layton15ecb432010-10-15 15:34:02 -0400240 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
241
Jeff Layton44772882010-10-15 15:34:03 -0400242 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400243 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
244 /* if readable file instance put first in list*/
245 if (file->f_mode & FMODE_READ)
246 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
247 else
248 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400249 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400250
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300251 cifs_set_oplock_level(pCifsInode, oplock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400252
253 file->private_data = pCifsFile;
254 return pCifsFile;
255}
256
Steve Frenchcdff08e2010-10-21 22:46:14 +0000257/*
258 * Release a reference on the file private data. This may involve closing
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400259 * the filehandle out on the server. Must be called without holding
260 * cifs_file_list_lock.
Steve Frenchcdff08e2010-10-21 22:46:14 +0000261 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400262void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
263{
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300264 struct inode *inode = cifs_file->dentry->d_inode;
Steve Frenchcdff08e2010-10-21 22:46:14 +0000265 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300266 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000267 struct cifsLockInfo *li, *tmp;
268
269 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400270 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000271 spin_unlock(&cifs_file_list_lock);
272 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400273 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000274
275 /* remove it from the lists */
276 list_del(&cifs_file->flist);
277 list_del(&cifs_file->tlist);
278
279 if (list_empty(&cifsi->openFileList)) {
280 cFYI(1, "closing last open instance for inode %p",
281 cifs_file->dentry->d_inode);
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300282 cifs_set_oplock_level(cifsi, 0);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000283 }
284 spin_unlock(&cifs_file_list_lock);
285
286 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
287 int xid, rc;
288
289 xid = GetXid();
290 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
291 FreeXid(xid);
292 }
293
294 /* Delete any outstanding lock records. We'll lose them when the file
295 * is closed anyway.
296 */
297 mutex_lock(&cifs_file->lock_mutex);
298 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
299 list_del(&li->llist);
300 kfree(li);
301 }
302 mutex_unlock(&cifs_file->lock_mutex);
303
304 cifs_put_tlink(cifs_file->tlink);
305 dput(cifs_file->dentry);
306 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400307}
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309int cifs_open(struct inode *inode, struct file *file)
310{
311 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400312 int xid;
313 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000315 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400316 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400317 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 char *full_path = NULL;
320 int desiredAccess;
321 int disposition;
322 __u16 netfid;
323 FILE_ALL_INFO *buf = NULL;
324
325 xid = GetXid();
326
327 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400328 tlink = cifs_sb_tlink(cifs_sb);
329 if (IS_ERR(tlink)) {
330 FreeXid(xid);
331 return PTR_ERR(tlink);
332 }
333 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Steve Frencha6ce4932009-04-09 01:14:32 +0000335 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800337 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530339 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400340 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342
Joe Perchesb6b38f72010-04-21 03:50:45 +0000343 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
344 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000345
346 if (oplockEnabled)
347 oplock = REQ_OPLOCK;
348 else
349 oplock = 0;
350
Steve French64cc2c62009-03-04 19:54:08 +0000351 if (!tcon->broken_posix_open && tcon->unix_ext &&
352 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000353 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
354 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000355 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400356 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000357 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400358 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000359 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000360 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400361
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400362 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
363 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400364 if (pCifsFile == NULL) {
365 CIFSSMBClose(xid, tcon, netfid);
366 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400367 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530368
369 cifs_fscache_set_inode_cookie(inode, file);
370
Steve French276a74a2009-03-03 18:00:34 +0000371 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000372 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
373 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000374 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000375 " unexpected error on SMB posix open"
376 ", disabling posix open support."
377 " Check if server update available.",
378 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000379 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000380 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000381 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
382 (rc != -EOPNOTSUPP)) /* path not found or net err */
383 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000384 /* else fallthrough to retry open the old way on network i/o
385 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000386 }
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 desiredAccess = cifs_convert_flags(file->f_flags);
389
390/*********************************************************************
391 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000392 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000394 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 * O_CREAT FILE_OPEN_IF
396 * O_CREAT | O_EXCL FILE_CREATE
397 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
398 * O_TRUNC FILE_OVERWRITE
399 * none of the above FILE_OPEN
400 *
401 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000402 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 * O_CREAT | O_TRUNC is similar but truncates the existing
404 * file rather than creating a new file as FILE_SUPERSEDE does
405 * (which uses the attributes / metadata passed in on open call)
406 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000407 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 *? and the read write flags match reasonably. O_LARGEFILE
409 *? is irrelevant because largefile support is always used
410 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
411 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
412 *********************************************************************/
413
414 disposition = cifs_get_disposition(file->f_flags);
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 /* BB pass O_SYNC flag through on file attributes .. BB */
417
418 /* Also refresh inode by passing in file_info buf returned by SMBOpen
419 and calling get_inode_info with returned buf (at least helps
420 non-Unix server case) */
421
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000422 /* BB we can not do this if this is the second open of a file
423 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
425 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
426 if (!buf) {
427 rc = -ENOMEM;
428 goto out;
429 }
Steve French5bafd762006-06-07 00:18:43 +0000430
Jeff Laytona6e8a842010-09-20 16:01:33 -0700431 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000432 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000433 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700434 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
435 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000436 else
437 rc = -EIO; /* no NT SMB support fall into legacy open below */
438
Steve Frencha9d02ad2005-08-24 23:06:05 -0700439 if (rc == -EIO) {
440 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000441 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700442 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
443 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
444 & CIFS_MOUNT_MAP_SPECIAL_CHR);
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000447 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 goto out;
449 }
Jeff Layton3321b792009-09-25 09:53:37 -0400450
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530451 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400452 if (rc != 0)
453 goto out;
454
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400455 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400456 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 rc = -ENOMEM;
458 goto out;
459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530461 cifs_fscache_set_inode_cookie(inode, file);
462
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 /* time to set mode which we can not set earlier due to
465 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000466 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400467 struct cifs_unix_set_info_args args = {
468 .mode = inode->i_mode,
469 .uid = NO_CHANGE_64,
470 .gid = NO_CHANGE_64,
471 .ctime = NO_CHANGE_64,
472 .atime = NO_CHANGE_64,
473 .mtime = NO_CHANGE_64,
474 .device = 0,
475 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400476 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
477 cifs_sb->local_nls,
478 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700479 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481 }
482
483out:
484 kfree(buf);
485 kfree(full_path);
486 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400487 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return rc;
489}
490
Adrian Bunk04187262006-06-30 18:23:04 +0200491/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492/* to server was lost */
493static int cifs_relock_file(struct cifsFileInfo *cifsFile)
494{
495 int rc = 0;
496
497/* BB list all locks open on this file and relock */
498
499 return rc;
500}
501
Jeff Layton15886172010-10-15 15:33:59 -0400502static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400505 int xid;
506 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000508 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000510 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 char *full_path = NULL;
512 int desiredAccess;
513 int disposition = FILE_OPEN;
514 __u16 netfid;
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400517 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000518 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400519 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530520 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530522 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524
Jeff Layton15886172010-10-15 15:33:59 -0400525 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400527 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529/* can not grab rename sem here because various ops, including
530 those that already have the rename sem can end up causing writepage
531 to get called and if the server was down that means we end up here,
532 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400533 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000535 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400536 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000538 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
540
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400542 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 if (oplockEnabled)
545 oplock = REQ_OPLOCK;
546 else
Steve French4b18f2a2008-04-29 00:06:05 +0000547 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Steve French7fc8f4e2009-02-23 20:43:11 +0000549 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
550 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
551 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400552
553 /*
554 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
555 * original open. Must mask them off for a reopen.
556 */
Jeff Layton15886172010-10-15 15:33:59 -0400557 unsigned int oflags = pCifsFile->f_flags &
558 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400559
Jeff Layton2422f672010-06-16 13:40:16 -0400560 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000561 cifs_sb->mnt_file_mode /* ignored */,
562 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000563 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000564 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000565 goto reopen_success;
566 }
567 /* fallthrough to retry open the old way on errors, especially
568 in the reconnect path it is important to retry hard */
569 }
570
Jeff Layton15886172010-10-15 15:33:59 -0400571 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 by SMBOpen and then calling get_inode_info with returned buf
575 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 and server version of file size can be stale. If we knew for sure
577 that inode was not dirty locally we could do this */
578
Steve French7fc8f4e2009-02-23 20:43:11 +0000579 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000581 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700582 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400584 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000585 cFYI(1, "cifs_open returned 0x%x", rc);
586 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400587 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
Jeff Layton15886172010-10-15 15:33:59 -0400589
590reopen_success:
591 pCifsFile->netfid = netfid;
592 pCifsFile->invalidHandle = false;
593 mutex_unlock(&pCifsFile->fh_mutex);
594 pCifsInode = CIFS_I(inode);
595
596 if (can_flush) {
597 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400598 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400599
Jeff Layton15886172010-10-15 15:33:59 -0400600 if (tcon->unix_ext)
601 rc = cifs_get_inode_info_unix(&inode,
602 full_path, inode->i_sb, xid);
603 else
604 rc = cifs_get_inode_info(&inode,
605 full_path, NULL, inode->i_sb,
606 xid, NULL);
607 } /* else we are writing out data to server already
608 and could deadlock if we tried to flush data, and
609 since we do not know if we have data that would
610 invalidate the current end of file on the server
611 we can not go to the server to get the new inod
612 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300613
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300614 cifs_set_oplock_level(pCifsInode, oplock);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300615
Jeff Layton15886172010-10-15 15:33:59 -0400616 cifs_relock_file(pCifsFile);
617
618reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 kfree(full_path);
620 FreeXid(xid);
621 return rc;
622}
623
624int cifs_close(struct inode *inode, struct file *file)
625{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000626 cifsFileInfo_put(file->private_data);
627 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Steve Frenchcdff08e2010-10-21 22:46:14 +0000629 /* return code from the ->release op is always ignored */
630 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633int cifs_closedir(struct inode *inode, struct file *file)
634{
635 int rc = 0;
636 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700637 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 char *ptmp;
639
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 xid = GetXid();
643
644 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400645 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400648 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000649 if (!pCFileStruct->srch_inf.endOfSearch &&
650 !pCFileStruct->invalidHandle) {
651 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400652 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cFYI(1, "Closing uncompleted readdir with rc %d",
655 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* not much we can do if it fails anyway, ignore rc */
657 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000658 } else
Jeff Layton44772882010-10-15 15:34:03 -0400659 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
661 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000664 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000665 cifs_small_buf_release(ptmp);
666 else
667 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400669 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 kfree(file->private_data);
671 file->private_data = NULL;
672 }
673 /* BB can we lock the filestruct while this is going on? */
674 FreeXid(xid);
675 return rc;
676}
677
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000678static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
679 __u64 offset, __u8 lockType)
680{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000681 struct cifsLockInfo *li =
682 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000683 if (li == NULL)
684 return -ENOMEM;
685 li->offset = offset;
686 li->length = len;
687 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000688 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000689 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000690 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000691 return 0;
692}
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
695{
696 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 __u32 numLock = 0;
698 __u32 numUnlock = 0;
699 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000700 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000702 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000703 __u16 netfid;
704 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000705 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 length = 1 + pfLock->fl_end - pfLock->fl_start;
708 rc = -EACCES;
709 xid = GetXid();
710
Joe Perchesb6b38f72010-04-21 03:50:45 +0000711 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000713 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000717 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000719 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000721 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000722 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000725 cFYI(1, "Process suspended by mandatory locking - "
726 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000728 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000729 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000731 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000734 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 numLock = 1;
736 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000737 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000739 /* Check if unlock includes more than
740 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000742 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 lockType |= LOCKING_ANDX_SHARED_LOCK;
744 numLock = 1;
745 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000746 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 numLock = 1;
748 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000749 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 lockType |= LOCKING_ANDX_SHARED_LOCK;
751 numLock = 1;
752 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800755 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400756 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Steve French08547b02006-02-28 22:39:25 +0000757 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Steve French13a6e422008-12-02 17:24:33 +0000759 if ((tcon->ses->capabilities & CAP_UNIX) &&
760 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000761 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000762 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000763 /* BB add code here to normalize offset and length to
764 account for negative length which we can not accept over the
765 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000767 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000768 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000769 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000770 posix_lock_type = CIFS_RDLCK;
771 else
772 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000773 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000774 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000775 posix_lock_type, wait_flag);
776 FreeXid(xid);
777 return rc;
778 }
779
780 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000781 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000782 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000784 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 pfLock->fl_start, 1 /* numUnlock */ ,
786 0 /* numLock */ , lockType,
787 0 /* wait flag */ );
788 pfLock->fl_type = F_UNLCK;
789 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000790 cERROR(1, "Error unlocking previously locked "
791 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 rc = 0;
793
794 } else {
795 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400796 rc = 0;
797
798 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
799 pfLock->fl_type = F_WRLCK;
800 } else {
801 rc = CIFSSMBLock(xid, tcon, netfid, length,
802 pfLock->fl_start, 0, 1,
803 lockType | LOCKING_ANDX_SHARED_LOCK,
804 0 /* wait flag */);
805 if (rc == 0) {
806 rc = CIFSSMBLock(xid, tcon, netfid,
807 length, pfLock->fl_start, 1, 0,
808 lockType |
809 LOCKING_ANDX_SHARED_LOCK,
810 0 /* wait flag */);
811 pfLock->fl_type = F_RDLCK;
812 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000813 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400814 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000815 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400816 rc = 0;
817 } else {
818 pfLock->fl_type = F_WRLCK;
819 rc = 0;
820 }
821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823
824 FreeXid(xid);
825 return rc;
826 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000827
828 if (!numLock && !numUnlock) {
829 /* if no lock or unlock then nothing
830 to do since we do not know what it is */
831 FreeXid(xid);
832 return -EOPNOTSUPP;
833 }
834
835 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000836 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000837 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000838 posix_lock_type = CIFS_RDLCK;
839 else
840 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000841
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000842 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000843 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000844
Steve French13a6e422008-12-02 17:24:33 +0000845 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000846 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000847 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000848 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700849 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000850
851 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000852 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000853 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000854 0, numLock, lockType, wait_flag);
855
856 if (rc == 0) {
857 /* For Windows locks we must store them. */
858 rc = store_file_lock(fid, length,
859 pfLock->fl_start, lockType);
860 }
861 } else if (numUnlock) {
862 /* For each stored lock that this unlock overlaps
863 completely, unlock it. */
864 int stored_rc = 0;
865 struct cifsLockInfo *li, *tmp;
866
Steve French6b70c952006-09-21 07:35:29 +0000867 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000868 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000869 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
870 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000871 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000872 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000873 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000874 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000875 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000876 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000877 if (stored_rc)
878 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000879 else {
880 list_del(&li->llist);
881 kfree(li);
882 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 }
884 }
Roland Dreier796e5662007-05-03 04:33:45 +0000885 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000886 }
887 }
888
Steve Frenchd634cc12005-08-26 14:42:59 -0500889 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 posix_lock_file_wait(file, pfLock);
891 FreeXid(xid);
892 return rc;
893}
894
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400895/*
896 * Set the timeout on write requests past EOF. For some servers (Windows)
897 * these calls can be very long.
898 *
899 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
900 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
901 * The 10M cutoff is totally arbitrary. A better scheme for this would be
902 * welcome if someone wants to suggest one.
903 *
904 * We may be able to do a better job with this if there were some way to
905 * declare that a file should be sparse.
906 */
907static int
908cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
909{
910 if (offset <= cifsi->server_eof)
911 return CIFS_STD_OP;
912 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
913 return CIFS_VLONG_OP;
914 else
915 return CIFS_LONG_OP;
916}
917
918/* update the file size (if needed) after a write */
919static void
920cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
921 unsigned int bytes_written)
922{
923 loff_t end_of_write = offset + bytes_written;
924
925 if (end_of_write > cifsi->server_eof)
926 cifsi->server_eof = end_of_write;
927}
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929ssize_t cifs_user_write(struct file *file, const char __user *write_data,
930 size_t write_size, loff_t *poffset)
931{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100932 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 int rc = 0;
934 unsigned int bytes_written = 0;
935 unsigned int total_written;
936 struct cifs_sb_info *cifs_sb;
937 struct cifsTconInfo *pTcon;
938 int xid, long_op;
939 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100940 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800942 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Joe Perchesb6b38f72010-04-21 03:50:45 +0000944 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
945 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 if (file->private_data == NULL)
948 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700949
Joe Perchesc21dfb62010-07-12 13:50:14 -0700950 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400951 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000952
Jeff Layton838726c2008-08-28 07:54:59 -0400953 rc = generic_write_checks(file, poffset, &write_size, 0);
954 if (rc)
955 return rc;
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400959 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 for (total_written = 0; write_size > total_written;
961 total_written += bytes_written) {
962 rc = -EAGAIN;
963 while (rc == -EAGAIN) {
964 if (file->private_data == NULL) {
965 /* file has been closed on us */
966 FreeXid(xid);
967 /* if we have gotten here we have written some data
968 and blocked, and the file has been freed on us while
969 we blocked so return what we managed to write */
970 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* we could deadlock if we called
974 filemap_fdatawait from here so tell
975 reopen_file not to flush data to server
976 now */
Jeff Layton15886172010-10-15 15:33:59 -0400977 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (rc != 0)
979 break;
980 }
981
982 rc = CIFSSMBWrite(xid, pTcon,
983 open_file->netfid,
984 min_t(const int, cifs_sb->wsize,
985 write_size - total_written),
986 *poffset, &bytes_written,
987 NULL, write_data + total_written, long_op);
988 }
989 if (rc || (bytes_written == 0)) {
990 if (total_written)
991 break;
992 else {
993 FreeXid(xid);
994 return rc;
995 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400996 } else {
997 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400999 }
Steve French133672e2007-11-13 22:41:37 +00001000 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 15 seconds is plenty */
1002 }
1003
Steve Frencha4544342005-08-24 13:59:35 -07001004 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001006/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001007 * inode->i_ctime = inode->i_mtime =
1008 * current_fs_time(inode->i_sb);*/
1009 if (total_written > 0) {
1010 spin_lock(&inode->i_lock);
1011 if (*poffset > inode->i_size)
1012 i_size_write(inode, *poffset);
1013 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001015 mark_inode_dirty_sync(inode);
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 FreeXid(xid);
1018 return total_written;
1019}
1020
Jeff Layton7da4b492010-10-15 15:34:00 -04001021static ssize_t cifs_write(struct cifsFileInfo *open_file,
1022 const char *write_data, size_t write_size,
1023 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 int rc = 0;
1026 unsigned int bytes_written = 0;
1027 unsigned int total_written;
1028 struct cifs_sb_info *cifs_sb;
1029 struct cifsTconInfo *pTcon;
1030 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001031 struct dentry *dentry = open_file->dentry;
1032 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Jeff Layton7da4b492010-10-15 15:34:00 -04001034 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Joe Perchesb6b38f72010-04-21 03:50:45 +00001036 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001037 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Jeff Layton13cfb732010-09-29 19:51:11 -04001039 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001043 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 for (total_written = 0; write_size > total_written;
1045 total_written += bytes_written) {
1046 rc = -EAGAIN;
1047 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 /* we could deadlock if we called
1050 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001051 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001053 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 if (rc != 0)
1055 break;
1056 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001057 if (experimEnabled || (pTcon->ses->server &&
1058 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001059 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001060 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001061 struct kvec iov[2];
1062 unsigned int len;
1063
Steve French0ae0efa2005-10-10 10:57:19 -07001064 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001065 write_size - total_written);
1066 /* iov[0] is reserved for smb header */
1067 iov[1].iov_base = (char *)write_data +
1068 total_written;
1069 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001070 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001071 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001072 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001073 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001074 } else
Steve French60808232006-04-22 15:53:05 +00001075 rc = CIFSSMBWrite(xid, pTcon,
1076 open_file->netfid,
1077 min_t(const int, cifs_sb->wsize,
1078 write_size - total_written),
1079 *poffset, &bytes_written,
1080 write_data + total_written,
1081 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083 if (rc || (bytes_written == 0)) {
1084 if (total_written)
1085 break;
1086 else {
1087 FreeXid(xid);
1088 return rc;
1089 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001090 } else {
1091 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001093 }
Steve French133672e2007-11-13 22:41:37 +00001094 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 15 seconds is plenty */
1096 }
1097
Steve Frencha4544342005-08-24 13:59:35 -07001098 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Jeff Layton7da4b492010-10-15 15:34:00 -04001100 if (total_written > 0) {
1101 spin_lock(&dentry->d_inode->i_lock);
1102 if (*poffset > dentry->d_inode->i_size)
1103 i_size_write(dentry->d_inode, *poffset);
1104 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001106 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 FreeXid(xid);
1108 return total_written;
1109}
1110
Jeff Layton6508d902010-09-29 19:51:11 -04001111struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1112 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001113{
1114 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001115 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1116
1117 /* only filter by fsuid on multiuser mounts */
1118 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1119 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001120
Jeff Layton44772882010-10-15 15:34:03 -04001121 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001122 /* we could simply get the first_list_entry since write-only entries
1123 are always at the end of the list but since the first entry might
1124 have a close pending, we go through the whole list */
1125 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001126 if (fsuid_only && open_file->uid != current_fsuid())
1127 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001128 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001129 if (!open_file->invalidHandle) {
1130 /* found a good file */
1131 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001132 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001133 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001134 return open_file;
1135 } /* else might as well continue, and look for
1136 another, or simply have the caller reopen it
1137 again rather than trying to fix this handle */
1138 } else /* write only file */
1139 break; /* write only files are last so must be done */
1140 }
Jeff Layton44772882010-10-15 15:34:03 -04001141 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001142 return NULL;
1143}
Steve French630f3f0c2007-10-25 21:17:17 +00001144
Jeff Layton6508d902010-09-29 19:51:11 -04001145struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1146 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001147{
1148 struct cifsFileInfo *open_file;
Jeff Laytond3892292010-11-02 16:22:50 -04001149 struct cifs_sb_info *cifs_sb;
Jeff Layton2846d382008-09-22 21:33:33 -04001150 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001151 int rc;
Steve French6148a742005-10-05 12:23:19 -07001152
Steve French60808232006-04-22 15:53:05 +00001153 /* Having a null inode here (because mapping->host was set to zero by
1154 the VFS or MM) should not happen but we had reports of on oops (due to
1155 it being zero) during stress testcases so we need to check for it */
1156
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001157 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001158 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001159 dump_stack();
1160 return NULL;
1161 }
1162
Jeff Laytond3892292010-11-02 16:22:50 -04001163 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1164
Jeff Layton6508d902010-09-29 19:51:11 -04001165 /* only filter by fsuid on multiuser mounts */
1166 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1167 fsuid_only = false;
1168
Jeff Layton44772882010-10-15 15:34:03 -04001169 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001170refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001171 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001172 if (!any_available && open_file->pid != current->tgid)
1173 continue;
1174 if (fsuid_only && open_file->uid != current_fsuid())
1175 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001176 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001177 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001178
1179 if (!open_file->invalidHandle) {
1180 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001181 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001182 return open_file;
1183 }
Steve French8840dee2007-11-16 23:05:52 +00001184
Jeff Layton44772882010-10-15 15:34:03 -04001185 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001186
Steve French9b22b0b2007-10-02 01:11:08 +00001187 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001188 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001189 if (!rc)
1190 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001191
Steve Frenchcdff08e2010-10-21 22:46:14 +00001192 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001193 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001194 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001195
Steve Frenchcdff08e2010-10-21 22:46:14 +00001196 spin_lock(&cifs_file_list_lock);
1197
Steve French9b22b0b2007-10-02 01:11:08 +00001198 /* else we simply continue to the next entry. Thus
1199 we do not loop on reopen errors. If we
1200 can not reopen the file, for example if we
1201 reconnected to a server with another client
1202 racing to delete or lock the file we would not
1203 make progress if we restarted before the beginning
1204 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001205 }
1206 }
Jeff Layton2846d382008-09-22 21:33:33 -04001207 /* couldn't find useable FH with same pid, try any available */
1208 if (!any_available) {
1209 any_available = true;
1210 goto refind_writable;
1211 }
Jeff Layton44772882010-10-15 15:34:03 -04001212 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001213 return NULL;
1214}
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1217{
1218 struct address_space *mapping = page->mapping;
1219 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1220 char *write_data;
1221 int rc = -EFAULT;
1222 int bytes_written = 0;
1223 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001225 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 if (!mapping || !mapping->host)
1228 return -EFAULT;
1229
1230 inode = page->mapping->host;
1231 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 offset += (loff_t)from;
1234 write_data = kmap(page);
1235 write_data += from;
1236
1237 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1238 kunmap(page);
1239 return -EIO;
1240 }
1241
1242 /* racing with truncate? */
1243 if (offset > mapping->host->i_size) {
1244 kunmap(page);
1245 return 0; /* don't care */
1246 }
1247
1248 /* check to make sure that we are not extending the file */
1249 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001250 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Jeff Layton6508d902010-09-29 19:51:11 -04001252 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001253 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001254 bytes_written = cifs_write(open_file, write_data,
1255 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001256 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001258 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001259 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001260 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001261 else if (bytes_written < 0)
1262 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001263 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001264 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 rc = -EIO;
1266 }
1267
1268 kunmap(page);
1269 return rc;
1270}
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001273 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
Steve French37c0eb42005-10-05 14:50:29 -07001275 unsigned int bytes_to_write;
1276 unsigned int bytes_written;
1277 struct cifs_sb_info *cifs_sb;
1278 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001279 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001280 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001281 int range_whole = 0;
1282 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001283 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001284 int n_iov = 0;
1285 pgoff_t next;
1286 int nr_pages;
1287 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001288 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001289 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001290 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001291 struct page *page;
1292 struct pagevec pvec;
1293 int rc = 0;
1294 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001295 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Steve French37c0eb42005-10-05 14:50:29 -07001297 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001298
Steve French37c0eb42005-10-05 14:50:29 -07001299 /*
1300 * If wsize is smaller that the page cache size, default to writing
1301 * one page at a time via cifs_writepage
1302 */
1303 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1304 return generic_writepages(mapping, wbc);
1305
Steve French9a0c8232007-02-02 04:21:57 +00001306 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001307 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001308 return generic_writepages(mapping, wbc);
1309
Steve French37c0eb42005-10-05 14:50:29 -07001310 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001311 * if there's no open file, then this is likely to fail too,
1312 * but it'll at least handle the return. Maybe it should be
1313 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001314 */
Jeff Layton6508d902010-09-29 19:51:11 -04001315 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001316 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001317 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001318 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001319 }
1320
Jeff Layton13cfb732010-09-29 19:51:11 -04001321 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001322 if (!experimEnabled && tcon->ses->server->secMode &
1323 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1324 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001325 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001326 return generic_writepages(mapping, wbc);
1327 }
1328 cifsFileInfo_put(open_file);
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 xid = GetXid();
1331
Steve French37c0eb42005-10-05 14:50:29 -07001332 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001333 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001334 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001335 end = -1;
1336 } else {
1337 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1338 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1339 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1340 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001341 scanned = 1;
1342 }
1343retry:
1344 while (!done && (index <= end) &&
1345 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1346 PAGECACHE_TAG_DIRTY,
1347 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1348 int first;
1349 unsigned int i;
1350
Steve French37c0eb42005-10-05 14:50:29 -07001351 first = -1;
1352 next = 0;
1353 n_iov = 0;
1354 bytes_to_write = 0;
1355
1356 for (i = 0; i < nr_pages; i++) {
1357 page = pvec.pages[i];
1358 /*
1359 * At this point we hold neither mapping->tree_lock nor
1360 * lock on the page itself: the page may be truncated or
1361 * invalidated (changing page->mapping to NULL), or even
1362 * swizzled back from swapper_space to tmpfs file
1363 * mapping
1364 */
1365
1366 if (first < 0)
1367 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001368 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001369 break;
1370
1371 if (unlikely(page->mapping != mapping)) {
1372 unlock_page(page);
1373 break;
1374 }
1375
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001376 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001377 done = 1;
1378 unlock_page(page);
1379 break;
1380 }
1381
1382 if (next && (page->index != next)) {
1383 /* Not next consecutive page */
1384 unlock_page(page);
1385 break;
1386 }
1387
1388 if (wbc->sync_mode != WB_SYNC_NONE)
1389 wait_on_page_writeback(page);
1390
1391 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001392 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001393 unlock_page(page);
1394 break;
1395 }
Steve French84d2f072005-10-12 15:32:05 -07001396
Linus Torvaldscb876f42006-12-23 16:19:07 -08001397 /*
1398 * This actually clears the dirty bit in the radix tree.
1399 * See cifs_writepage() for more commentary.
1400 */
1401 set_page_writeback(page);
1402
Steve French84d2f072005-10-12 15:32:05 -07001403 if (page_offset(page) >= mapping->host->i_size) {
1404 done = 1;
1405 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001406 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001407 break;
1408 }
1409
Steve French37c0eb42005-10-05 14:50:29 -07001410 /*
1411 * BB can we get rid of this? pages are held by pvec
1412 */
1413 page_cache_get(page);
1414
Steve French84d2f072005-10-12 15:32:05 -07001415 len = min(mapping->host->i_size - page_offset(page),
1416 (loff_t)PAGE_CACHE_SIZE);
1417
Steve French37c0eb42005-10-05 14:50:29 -07001418 /* reserve iov[0] for the smb header */
1419 n_iov++;
1420 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001421 iov[n_iov].iov_len = len;
1422 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001423
1424 if (first < 0) {
1425 first = i;
1426 offset = page_offset(page);
1427 }
1428 next = page->index + 1;
1429 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1430 break;
1431 }
1432 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001433 open_file = find_writable_file(CIFS_I(mapping->host),
1434 false);
Steve French23e7dd72005-10-20 13:44:56 -07001435 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001436 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001437 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001438 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001439 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001440 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001441 bytes_to_write, offset,
1442 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001443 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001444 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001445 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001446 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001447
1448 if (rc || bytes_written < bytes_to_write) {
1449 cERROR(1, "Write2 ret %d, wrote %d",
1450 rc, bytes_written);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001451 mapping_set_error(mapping, rc);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001452 } else {
1453 cifs_stats_bytes_written(tcon, bytes_written);
1454 }
1455
Steve French37c0eb42005-10-05 14:50:29 -07001456 for (i = 0; i < n_iov; i++) {
1457 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001458 /* Should we also set page error on
1459 success rc but too little data written? */
1460 /* BB investigate retry logic on temporary
1461 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001462 when page marked as error */
1463 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001464 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001465 kunmap(page);
1466 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001467 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001468 page_cache_release(page);
1469 }
1470 if ((wbc->nr_to_write -= n_iov) <= 0)
1471 done = 1;
1472 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001473 } else
1474 /* Need to re-find the pages we skipped */
1475 index = pvec.pages[0]->index + 1;
1476
Steve French37c0eb42005-10-05 14:50:29 -07001477 pagevec_release(&pvec);
1478 }
1479 if (!scanned && !done) {
1480 /*
1481 * We hit the last page and there is more work to be done: wrap
1482 * back to the start of the file
1483 */
1484 scanned = 1;
1485 index = 0;
1486 goto retry;
1487 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001488 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001489 mapping->writeback_index = index;
1490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001492 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return rc;
1494}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001496static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
1498 int rc = -EFAULT;
1499 int xid;
1500
1501 xid = GetXid();
1502/* BB add check for wbc flags */
1503 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001504 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001505 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001506
1507 /*
1508 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1509 *
1510 * A writepage() implementation always needs to do either this,
1511 * or re-dirty the page with "redirty_page_for_writepage()" in
1512 * the case of a failure.
1513 *
1514 * Just unlocking the page will cause the radix tree tag-bits
1515 * to fail to update with the state of the page correctly.
1516 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001517 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1519 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1520 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001521 end_page_writeback(page);
1522 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 FreeXid(xid);
1524 return rc;
1525}
1526
Nick Piggind9414772008-09-24 11:32:59 -04001527static int cifs_write_end(struct file *file, struct address_space *mapping,
1528 loff_t pos, unsigned len, unsigned copied,
1529 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530{
Nick Piggind9414772008-09-24 11:32:59 -04001531 int rc;
1532 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
Joe Perchesb6b38f72010-04-21 03:50:45 +00001534 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1535 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001536
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001537 if (PageChecked(page)) {
1538 if (copied == len)
1539 SetPageUptodate(page);
1540 ClearPageChecked(page);
1541 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001542 SetPageUptodate(page);
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001545 char *page_data;
1546 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1547 int xid;
1548
1549 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 /* this is probably better than directly calling
1551 partialpage_write since in this function the file handle is
1552 known which we might as well leverage */
1553 /* BB check if anything else missing out of ppw
1554 such as updating last write time */
1555 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001556 rc = cifs_write(file->private_data, page_data + offset,
1557 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001558 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001560
1561 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001562 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001563 rc = copied;
1564 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 set_page_dirty(page);
1566 }
1567
Nick Piggind9414772008-09-24 11:32:59 -04001568 if (rc > 0) {
1569 spin_lock(&inode->i_lock);
1570 if (pos > inode->i_size)
1571 i_size_write(inode, pos);
1572 spin_unlock(&inode->i_lock);
1573 }
1574
1575 unlock_page(page);
1576 page_cache_release(page);
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return rc;
1579}
1580
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001581int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
1583 int xid;
1584 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001585 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001586 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001587 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 xid = GetXid();
1590
Joe Perchesb6b38f72010-04-21 03:50:45 +00001591 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001592 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001593
Jeff Laytoncea21802007-11-20 23:19:03 +00001594 rc = filemap_write_and_wait(inode->i_mapping);
1595 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001596 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1597
Jeff Layton13cfb732010-09-29 19:51:11 -04001598 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001599 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001600 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001601 }
Steve Frenchb298f222009-02-21 21:17:43 +00001602
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 FreeXid(xid);
1604 return rc;
1605}
1606
NeilBrown3978d7172006-03-26 01:37:17 -08001607/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 struct address_space *mapping;
1610 struct inode *inode;
1611 unsigned long index = page->index;
1612 unsigned int rpages = 0;
1613 int rc = 0;
1614
Steve Frenchf19159d2010-04-21 04:12:10 +00001615 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 mapping = page->mapping;
1617 if (!mapping)
1618 return 0;
1619 inode = mapping->host;
1620 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001621 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001623/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1625
Joe Perchesb6b38f72010-04-21 03:50:45 +00001626/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
NeilBrown3978d7172006-03-26 01:37:17 -08001628#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (rc < 0)
1630 return rc;
1631 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633} */
1634
1635/*
1636 * As file closes, flush all cached write data for this inode checking
1637 * for write behind errors.
1638 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001639int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001641 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 int rc = 0;
1643
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001644 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001645 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001646
Joe Perchesb6b38f72010-04-21 03:50:45 +00001647 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 return rc;
1650}
1651
1652ssize_t cifs_user_read(struct file *file, char __user *read_data,
1653 size_t read_size, loff_t *poffset)
1654{
1655 int rc = -EACCES;
1656 unsigned int bytes_read = 0;
1657 unsigned int total_read = 0;
1658 unsigned int current_read_size;
1659 struct cifs_sb_info *cifs_sb;
1660 struct cifsTconInfo *pTcon;
1661 int xid;
1662 struct cifsFileInfo *open_file;
1663 char *smb_read_data;
1664 char __user *current_offset;
1665 struct smb_com_read_rsp *pSMBr;
1666
1667 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001668 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301671 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301673 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001675 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001676 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Steve Frenchad7a2922008-02-07 23:25:02 +00001678 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001679 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 for (total_read = 0, current_offset = read_data;
1682 read_size > total_read;
1683 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001684 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 cifs_sb->rsize);
1686 rc = -EAGAIN;
1687 smb_read_data = NULL;
1688 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001689 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001690 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001691 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 if (rc != 0)
1693 break;
1694 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001695 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001696 open_file->netfid,
1697 current_read_size, *poffset,
1698 &bytes_read, &smb_read_data,
1699 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001702 if (copy_to_user(current_offset,
1703 smb_read_data +
1704 4 /* RFC1001 length field */ +
1705 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001706 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001707 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001708
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001709 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001710 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001711 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001712 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 smb_read_data = NULL;
1714 }
1715 }
1716 if (rc || (bytes_read == 0)) {
1717 if (total_read) {
1718 break;
1719 } else {
1720 FreeXid(xid);
1721 return rc;
1722 }
1723 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001724 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 *poffset += bytes_read;
1726 }
1727 }
1728 FreeXid(xid);
1729 return total_read;
1730}
1731
1732
1733static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1734 loff_t *poffset)
1735{
1736 int rc = -EACCES;
1737 unsigned int bytes_read = 0;
1738 unsigned int total_read;
1739 unsigned int current_read_size;
1740 struct cifs_sb_info *cifs_sb;
1741 struct cifsTconInfo *pTcon;
1742 int xid;
1743 char *current_offset;
1744 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001745 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001748 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301751 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301753 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001755 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001756 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001759 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001761 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 read_size > total_read;
1763 total_read += bytes_read, current_offset += bytes_read) {
1764 current_read_size = min_t(const int, read_size - total_read,
1765 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001766 /* For windows me and 9x we do not want to request more
1767 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001769 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1770 current_read_size = min_t(const int, current_read_size,
1771 pTcon->ses->server->maxBuf - 128);
1772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 rc = -EAGAIN;
1774 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001775 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001776 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 if (rc != 0)
1778 break;
1779 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001780 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001781 open_file->netfid,
1782 current_read_size, *poffset,
1783 &bytes_read, &current_offset,
1784 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786 if (rc || (bytes_read == 0)) {
1787 if (total_read) {
1788 break;
1789 } else {
1790 FreeXid(xid);
1791 return rc;
1792 }
1793 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001794 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 *poffset += bytes_read;
1796 }
1797 }
1798 FreeXid(xid);
1799 return total_read;
1800}
1801
1802int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1803{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 int rc, xid;
1805
1806 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001807 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001809 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 FreeXid(xid);
1811 return rc;
1812 }
1813 rc = generic_file_mmap(file, vma);
1814 FreeXid(xid);
1815 return rc;
1816}
1817
1818
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001819static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001820 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 struct page *page;
1823 char *target;
1824
1825 while (bytes_read > 0) {
1826 if (list_empty(pages))
1827 break;
1828
1829 page = list_entry(pages->prev, struct page, lru);
1830 list_del(&page->lru);
1831
Nick Piggin315e9952010-04-21 03:18:28 +00001832 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 GFP_KERNEL)) {
1834 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001835 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001836 data += PAGE_CACHE_SIZE;
1837 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 continue;
1839 }
Jeff Layton06b43672010-06-01 10:54:45 -04001840 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001842 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 if (PAGE_CACHE_SIZE > bytes_read) {
1845 memcpy(target, data, bytes_read);
1846 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001847 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 PAGE_CACHE_SIZE - bytes_read);
1849 bytes_read = 0;
1850 } else {
1851 memcpy(target, data, PAGE_CACHE_SIZE);
1852 bytes_read -= PAGE_CACHE_SIZE;
1853 }
1854 kunmap_atomic(target, KM_USER0);
1855
1856 flush_dcache_page(page);
1857 SetPageUptodate(page);
1858 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301860
1861 /* add page to FS-Cache */
1862 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
1864 return;
1865}
1866
1867static int cifs_readpages(struct file *file, struct address_space *mapping,
1868 struct list_head *page_list, unsigned num_pages)
1869{
1870 int rc = -EACCES;
1871 int xid;
1872 loff_t offset;
1873 struct page *page;
1874 struct cifs_sb_info *cifs_sb;
1875 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001876 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001877 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 char *smb_read_data = NULL;
1879 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001881 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
1883 xid = GetXid();
1884 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301885 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301887 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001889 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001890 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001891 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001892
Suresh Jayaraman56698232010-07-05 18:13:25 +05301893 /*
1894 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1895 * immediately if the cookie is negative
1896 */
1897 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1898 &num_pages);
1899 if (rc == 0)
1900 goto read_complete;
1901
Steve Frenchf19159d2010-04-21 04:12:10 +00001902 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 for (i = 0; i < num_pages; ) {
1904 unsigned contig_pages;
1905 struct page *tmp_page;
1906 unsigned long expected_index;
1907
1908 if (list_empty(page_list))
1909 break;
1910
1911 page = list_entry(page_list->prev, struct page, lru);
1912 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1913
1914 /* count adjacent pages that we will read into */
1915 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001916 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001918 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 if (tmp_page->index == expected_index) {
1920 contig_pages++;
1921 expected_index++;
1922 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001923 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 }
1925 if (contig_pages + i > num_pages)
1926 contig_pages = num_pages - i;
1927
1928 /* for reads over a certain size could initiate async
1929 read ahead */
1930
1931 read_size = contig_pages * PAGE_CACHE_SIZE;
1932 /* Read size needs to be in multiples of one page */
1933 read_size = min_t(const unsigned int, read_size,
1934 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001935 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1936 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 rc = -EAGAIN;
1938 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001939 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001940 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (rc != 0)
1942 break;
1943 }
1944
Steve Frenchbfa0d752005-08-31 21:50:37 -07001945 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001946 open_file->netfid,
1947 read_size, offset,
1948 &bytes_read, &smb_read_data,
1949 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001950 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001951 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001953 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001954 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001955 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001956 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 smb_read_data = NULL;
1958 }
1959 }
1960 }
1961 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001962 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 break;
1964 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001965 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1967 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1968 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001969 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001972 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001973 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 i++; /* account for partial page */
1975
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001978 /* BB do we need to verify this common case ?
1979 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 we will hit it on next read */
1981
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001982 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 }
1984 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001985 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001986 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001987 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001988 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 break;
1991 }
1992 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001993 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001994 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001995 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001996 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 smb_read_data = NULL;
1998 }
1999 bytes_read = 0;
2000 }
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002/* need to free smb_read_data buf before exit */
2003 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002004 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002005 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002006 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002007 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Suresh Jayaraman56698232010-07-05 18:13:25 +05302011read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 FreeXid(xid);
2013 return rc;
2014}
2015
2016static int cifs_readpage_worker(struct file *file, struct page *page,
2017 loff_t *poffset)
2018{
2019 char *read_data;
2020 int rc;
2021
Suresh Jayaraman56698232010-07-05 18:13:25 +05302022 /* Is the page cached? */
2023 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2024 if (rc == 0)
2025 goto read_complete;
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 page_cache_get(page);
2028 read_data = kmap(page);
2029 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (rc < 0)
2034 goto io_error;
2035 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002036 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002038 file->f_path.dentry->d_inode->i_atime =
2039 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 if (PAGE_CACHE_SIZE > rc)
2042 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2043
2044 flush_dcache_page(page);
2045 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302046
2047 /* send this page to the cache */
2048 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2049
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002053 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302055
2056read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return rc;
2058}
2059
2060static int cifs_readpage(struct file *file, struct page *page)
2061{
2062 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2063 int rc = -EACCES;
2064 int xid;
2065
2066 xid = GetXid();
2067
2068 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302069 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302071 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 }
2073
Joe Perchesb6b38f72010-04-21 03:50:45 +00002074 cFYI(1, "readpage %p at offset %d 0x%x\n",
2075 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
2077 rc = cifs_readpage_worker(file, page, &offset);
2078
2079 unlock_page(page);
2080
2081 FreeXid(xid);
2082 return rc;
2083}
2084
Steve Frencha403a0a2007-07-26 15:54:16 +00002085static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2086{
2087 struct cifsFileInfo *open_file;
2088
Jeff Layton44772882010-10-15 15:34:03 -04002089 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002090 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002091 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002092 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002093 return 1;
2094 }
2095 }
Jeff Layton44772882010-10-15 15:34:03 -04002096 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002097 return 0;
2098}
2099
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100/* We do not want to update the file size from server for inodes
2101 open for write - to avoid races with writepage extending
2102 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002103 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 but this is tricky to do without racing with writebehind
2105 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002106bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
Steve Frencha403a0a2007-07-26 15:54:16 +00002108 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002109 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002110
Steve Frencha403a0a2007-07-26 15:54:16 +00002111 if (is_inode_writable(cifsInode)) {
2112 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002113 struct cifs_sb_info *cifs_sb;
2114
Steve Frenchc32a0b62006-01-12 14:41:28 -08002115 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002116 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002117 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002118 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002119 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002120 }
2121
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002122 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002123 return true;
Steve French7ba52632007-02-08 18:14:13 +00002124
Steve French4b18f2a2008-04-29 00:06:05 +00002125 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002126 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002127 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}
2129
Nick Piggind9414772008-09-24 11:32:59 -04002130static int cifs_write_begin(struct file *file, struct address_space *mapping,
2131 loff_t pos, unsigned len, unsigned flags,
2132 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133{
Nick Piggind9414772008-09-24 11:32:59 -04002134 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2135 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002136 loff_t page_start = pos & PAGE_MASK;
2137 loff_t i_size;
2138 struct page *page;
2139 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Joe Perchesb6b38f72010-04-21 03:50:45 +00002141 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002142
Nick Piggin54566b22009-01-04 12:00:53 -08002143 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002144 if (!page) {
2145 rc = -ENOMEM;
2146 goto out;
2147 }
Nick Piggind9414772008-09-24 11:32:59 -04002148
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002149 if (PageUptodate(page))
2150 goto out;
Steve French8a236262007-03-06 00:31:00 +00002151
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002152 /*
2153 * If we write a full page it will be up to date, no need to read from
2154 * the server. If the write is short, we'll end up doing a sync write
2155 * instead.
2156 */
2157 if (len == PAGE_CACHE_SIZE)
2158 goto out;
2159
2160 /*
2161 * optimize away the read when we have an oplock, and we're not
2162 * expecting to use any of the data we'd be reading in. That
2163 * is, when the page lies beyond the EOF, or straddles the EOF
2164 * and the write will cover all of the existing data.
2165 */
2166 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2167 i_size = i_size_read(mapping->host);
2168 if (page_start >= i_size ||
2169 (offset == 0 && (pos + len) >= i_size)) {
2170 zero_user_segments(page, 0, offset,
2171 offset + len,
2172 PAGE_CACHE_SIZE);
2173 /*
2174 * PageChecked means that the parts of the page
2175 * to which we're not writing are considered up
2176 * to date. Once the data is copied to the
2177 * page, it can be set uptodate.
2178 */
2179 SetPageChecked(page);
2180 goto out;
2181 }
2182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Nick Piggind9414772008-09-24 11:32:59 -04002184 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002185 /*
2186 * might as well read a page, it is fast enough. If we get
2187 * an error, we don't need to return it. cifs_write_end will
2188 * do a sync write instead since PG_uptodate isn't set.
2189 */
2190 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002191 } else {
2192 /* we could try using another file handle if there is one -
2193 but how would we lock it to prevent close of that handle
2194 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002195 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002196 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002197out:
2198 *pagep = page;
2199 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200}
2201
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302202static int cifs_release_page(struct page *page, gfp_t gfp)
2203{
2204 if (PagePrivate(page))
2205 return 0;
2206
2207 return cifs_fscache_release_page(page, gfp);
2208}
2209
2210static void cifs_invalidate_page(struct page *page, unsigned long offset)
2211{
2212 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2213
2214 if (offset == 0)
2215 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2216}
2217
Tejun Heo9b646972010-07-20 22:09:02 +02002218void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002219{
2220 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2221 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002222 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002223 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002224 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002225
2226 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002227 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002228 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002229 else
Al Viro8737c932009-12-24 06:47:55 -05002230 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002231 rc = filemap_fdatawrite(inode->i_mapping);
2232 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002233 rc = filemap_fdatawait(inode->i_mapping);
2234 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002235 invalidate_remote_inode(inode);
2236 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002237 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002238 }
2239
2240 /*
2241 * releasing stale oplock after recent reconnect of smb session using
2242 * a now incorrect file handle is not a data integrity issue but do
2243 * not bother sending an oplock release if session to server still is
2244 * disconnected since oplock already released by the server
2245 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002246 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002247 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2248 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002249 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002250 }
Tejun Heo9b646972010-07-20 22:09:02 +02002251
2252 /*
2253 * We might have kicked in before is_valid_oplock_break()
2254 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302255 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002256 */
Jeff Layton44772882010-10-15 15:34:03 -04002257 spin_lock(&cifs_file_list_lock);
2258 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002259
2260 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002261}
2262
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002263/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002264void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002265{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002266 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002267 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002268}
2269
Tejun Heo9b646972010-07-20 22:09:02 +02002270void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002271{
Jeff Laytonebe2e912010-11-10 10:19:10 -05002272 struct super_block *sb = cfile->dentry->d_sb;
2273
Jeff Layton3bc303c2009-09-21 06:47:50 -04002274 cifsFileInfo_put(cfile);
Jeff Laytonebe2e912010-11-10 10:19:10 -05002275 cifs_sb_deactive(sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002276}
2277
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002278const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 .readpage = cifs_readpage,
2280 .readpages = cifs_readpages,
2281 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002282 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002283 .write_begin = cifs_write_begin,
2284 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302286 .releasepage = cifs_release_page,
2287 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 /* .sync_page = cifs_sync_page, */
2289 /* .direct_IO = */
2290};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002291
2292/*
2293 * cifs_readpages requires the server to support a buffer large enough to
2294 * contain the header plus one complete page of data. Otherwise, we need
2295 * to leave cifs_readpages out of the address space operations.
2296 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002297const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002298 .readpage = cifs_readpage,
2299 .writepage = cifs_writepage,
2300 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002301 .write_begin = cifs_write_begin,
2302 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002303 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302304 .releasepage = cifs_release_page,
2305 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002306 /* .sync_page = cifs_sync_page, */
2307 /* .direct_IO = */
2308};