blob: 97ddbf2fdfc3aa46ebf0a9692e58993574e1ce4e [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 Layton608712f2010-10-15 15:33:56 -0400107int cifs_posix_open(char *full_path, struct inode **pinode,
108 struct super_block *sb, int mode, unsigned int f_flags,
109 __u32 *poplock, __u16 *pnetfid, int xid)
110{
111 int rc;
112 FILE_UNIX_BASIC_INFO *presp_data;
113 __u32 posix_flags = 0;
114 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
115 struct cifs_fattr fattr;
116 struct tcon_link *tlink;
117 struct cifsTconInfo *tcon;
118
119 cFYI(1, "posix open %s", full_path);
120
121 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
122 if (presp_data == NULL)
123 return -ENOMEM;
124
125 tlink = cifs_sb_tlink(cifs_sb);
126 if (IS_ERR(tlink)) {
127 rc = PTR_ERR(tlink);
128 goto posix_open_ret;
129 }
130
131 tcon = tlink_tcon(tlink);
132 mode &= ~current_umask();
133
134 posix_flags = cifs_posix_convert_flags(f_flags);
135 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
136 poplock, full_path, cifs_sb->local_nls,
137 cifs_sb->mnt_cifs_flags &
138 CIFS_MOUNT_MAP_SPECIAL_CHR);
139 cifs_put_tlink(tlink);
140
141 if (rc)
142 goto posix_open_ret;
143
144 if (presp_data->Type == cpu_to_le32(-1))
145 goto posix_open_ret; /* open ok, caller does qpathinfo */
146
147 if (!pinode)
148 goto posix_open_ret; /* caller does not need info */
149
150 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
151
152 /* get new inode and set it up */
153 if (*pinode == NULL) {
154 cifs_fill_uniqueid(sb, &fattr);
155 *pinode = cifs_iget(sb, &fattr);
156 if (!*pinode) {
157 rc = -ENOMEM;
158 goto posix_open_ret;
159 }
160 } else {
161 cifs_fattr_to_inode(*pinode, &fattr);
162 }
163
164posix_open_ret:
165 kfree(presp_data);
166 return rc;
167}
168
Pavel Shilovskyeeb910a2010-11-25 15:12:39 +0300169static int
170cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
171 struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock,
172 __u16 *pnetfid, int xid)
173{
174 int rc;
175 int desiredAccess;
176 int disposition;
177 FILE_ALL_INFO *buf;
178
179 desiredAccess = cifs_convert_flags(f_flags);
180
181/*********************************************************************
182 * open flag mapping table:
183 *
184 * POSIX Flag CIFS Disposition
185 * ---------- ----------------
186 * O_CREAT FILE_OPEN_IF
187 * O_CREAT | O_EXCL FILE_CREATE
188 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
189 * O_TRUNC FILE_OVERWRITE
190 * none of the above FILE_OPEN
191 *
192 * Note that there is not a direct match between disposition
193 * FILE_SUPERSEDE (ie create whether or not file exists although
194 * O_CREAT | O_TRUNC is similar but truncates the existing
195 * file rather than creating a new file as FILE_SUPERSEDE does
196 * (which uses the attributes / metadata passed in on open call)
197 *?
198 *? O_SYNC is a reasonable match to CIFS writethrough flag
199 *? and the read write flags match reasonably. O_LARGEFILE
200 *? is irrelevant because largefile support is always used
201 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
202 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
203 *********************************************************************/
204
205 disposition = cifs_get_disposition(f_flags);
206
207 /* BB pass O_SYNC flag through on file attributes .. BB */
208
209 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
210 if (!buf)
211 return -ENOMEM;
212
213 if (tcon->ses->capabilities & CAP_NT_SMBS)
214 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
215 desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
216 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
217 & CIFS_MOUNT_MAP_SPECIAL_CHR);
218 else
219 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
220 desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
221 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
222 & CIFS_MOUNT_MAP_SPECIAL_CHR);
223
224 if (rc)
225 goto out;
226
227 if (tcon->unix_ext)
228 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
229 xid);
230 else
231 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
232 xid, pnetfid);
233
234out:
235 kfree(buf);
236 return rc;
237}
238
Jeff Layton15ecb432010-10-15 15:34:02 -0400239struct cifsFileInfo *
240cifs_new_fileinfo(__u16 fileHandle, struct file *file,
241 struct tcon_link *tlink, __u32 oplock)
242{
243 struct dentry *dentry = file->f_path.dentry;
244 struct inode *inode = dentry->d_inode;
245 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
246 struct cifsFileInfo *pCifsFile;
247
248 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
249 if (pCifsFile == NULL)
250 return pCifsFile;
251
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400252 pCifsFile->count = 1;
Jeff Layton15ecb432010-10-15 15:34:02 -0400253 pCifsFile->netfid = fileHandle;
254 pCifsFile->pid = current->tgid;
255 pCifsFile->uid = current_fsuid();
256 pCifsFile->dentry = dget(dentry);
257 pCifsFile->f_flags = file->f_flags;
258 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400259 pCifsFile->tlink = cifs_get_tlink(tlink);
260 mutex_init(&pCifsFile->fh_mutex);
261 mutex_init(&pCifsFile->lock_mutex);
262 INIT_LIST_HEAD(&pCifsFile->llist);
Jeff Layton15ecb432010-10-15 15:34:02 -0400263 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
264
Jeff Layton44772882010-10-15 15:34:03 -0400265 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400266 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
267 /* if readable file instance put first in list*/
268 if (file->f_mode & FMODE_READ)
269 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
270 else
271 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400272 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400273
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300274 cifs_set_oplock_level(pCifsInode, oplock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400275
276 file->private_data = pCifsFile;
277 return pCifsFile;
278}
279
Steve Frenchcdff08e2010-10-21 22:46:14 +0000280/*
281 * Release a reference on the file private data. This may involve closing
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400282 * the filehandle out on the server. Must be called without holding
283 * cifs_file_list_lock.
Steve Frenchcdff08e2010-10-21 22:46:14 +0000284 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400285void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
286{
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300287 struct inode *inode = cifs_file->dentry->d_inode;
Steve Frenchcdff08e2010-10-21 22:46:14 +0000288 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300289 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000290 struct cifsLockInfo *li, *tmp;
291
292 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400293 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000294 spin_unlock(&cifs_file_list_lock);
295 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400296 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000297
298 /* remove it from the lists */
299 list_del(&cifs_file->flist);
300 list_del(&cifs_file->tlist);
301
302 if (list_empty(&cifsi->openFileList)) {
303 cFYI(1, "closing last open instance for inode %p",
304 cifs_file->dentry->d_inode);
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300305 cifs_set_oplock_level(cifsi, 0);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000306 }
307 spin_unlock(&cifs_file_list_lock);
308
309 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
310 int xid, rc;
311
312 xid = GetXid();
313 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
314 FreeXid(xid);
315 }
316
317 /* Delete any outstanding lock records. We'll lose them when the file
318 * is closed anyway.
319 */
320 mutex_lock(&cifs_file->lock_mutex);
321 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
322 list_del(&li->llist);
323 kfree(li);
324 }
325 mutex_unlock(&cifs_file->lock_mutex);
326
327 cifs_put_tlink(cifs_file->tlink);
328 dput(cifs_file->dentry);
329 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332int cifs_open(struct inode *inode, struct file *file)
333{
334 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400335 int xid;
336 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000338 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400339 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400340 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 char *full_path = NULL;
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300343 bool posix_open_ok = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 __u16 netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 xid = GetXid();
347
348 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400349 tlink = cifs_sb_tlink(cifs_sb);
350 if (IS_ERR(tlink)) {
351 FreeXid(xid);
352 return PTR_ERR(tlink);
353 }
354 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Steve Frencha6ce4932009-04-09 01:14:32 +0000356 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800358 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530360 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400361 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
363
Joe Perchesb6b38f72010-04-21 03:50:45 +0000364 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
365 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000366
367 if (oplockEnabled)
368 oplock = REQ_OPLOCK;
369 else
370 oplock = 0;
371
Steve French64cc2c62009-03-04 19:54:08 +0000372 if (!tcon->broken_posix_open && tcon->unix_ext &&
373 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000374 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
375 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000376 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400377 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000378 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400379 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000380 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000381 cFYI(1, "posix open succeeded");
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300382 posix_open_ok = true;
Steve French64cc2c62009-03-04 19:54:08 +0000383 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
384 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000385 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000386 " unexpected error on SMB posix open"
387 ", disabling posix open support."
388 " Check if server update available.",
389 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000390 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000391 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000392 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
393 (rc != -EOPNOTSUPP)) /* path not found or net err */
394 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000395 /* else fallthrough to retry open the old way on network i/o
396 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000397 }
398
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300399 if (!posix_open_ok) {
400 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
401 file->f_flags, &oplock, &netfid, xid);
402 if (rc)
403 goto out;
404 }
Jeff Layton47c78b72010-06-16 13:40:17 -0400405
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400406 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400407 if (pCifsFile == NULL) {
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300408 CIFSSMBClose(xid, tcon, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 rc = -ENOMEM;
410 goto out;
411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530413 cifs_fscache_set_inode_cookie(inode, file);
414
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300415 if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 /* time to set mode which we can not set earlier due to
417 problems creating new read-only files */
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300418 struct cifs_unix_set_info_args args = {
419 .mode = inode->i_mode,
420 .uid = NO_CHANGE_64,
421 .gid = NO_CHANGE_64,
422 .ctime = NO_CHANGE_64,
423 .atime = NO_CHANGE_64,
424 .mtime = NO_CHANGE_64,
425 .device = 0,
426 };
427 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
428 cifs_sb->local_nls,
429 cifs_sb->mnt_cifs_flags &
430 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 }
432
433out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 kfree(full_path);
435 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400436 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 return rc;
438}
439
Adrian Bunk04187262006-06-30 18:23:04 +0200440/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441/* to server was lost */
442static int cifs_relock_file(struct cifsFileInfo *cifsFile)
443{
444 int rc = 0;
445
446/* BB list all locks open on this file and relock */
447
448 return rc;
449}
450
Jeff Layton15886172010-10-15 15:33:59 -0400451static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400454 int xid;
455 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000457 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 char *full_path = NULL;
461 int desiredAccess;
462 int disposition = FILE_OPEN;
463 __u16 netfid;
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400466 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000467 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400468 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530469 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530471 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473
Jeff Layton15886172010-10-15 15:33:59 -0400474 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400476 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478/* can not grab rename sem here because various ops, including
479 those that already have the rename sem can end up causing writepage
480 to get called and if the server was down that means we end up here,
481 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400482 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000484 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400485 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000487 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 }
489
Joe Perchesb6b38f72010-04-21 03:50:45 +0000490 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400491 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 if (oplockEnabled)
494 oplock = REQ_OPLOCK;
495 else
Steve French4b18f2a2008-04-29 00:06:05 +0000496 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Steve French7fc8f4e2009-02-23 20:43:11 +0000498 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
499 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
500 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400501
502 /*
503 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
504 * original open. Must mask them off for a reopen.
505 */
Jeff Layton15886172010-10-15 15:33:59 -0400506 unsigned int oflags = pCifsFile->f_flags &
507 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400508
Jeff Layton2422f672010-06-16 13:40:16 -0400509 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000510 cifs_sb->mnt_file_mode /* ignored */,
511 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000512 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000513 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000514 goto reopen_success;
515 }
516 /* fallthrough to retry open the old way on errors, especially
517 in the reconnect path it is important to retry hard */
518 }
519
Jeff Layton15886172010-10-15 15:33:59 -0400520 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000523 by SMBOpen and then calling get_inode_info with returned buf
524 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 and server version of file size can be stale. If we knew for sure
526 that inode was not dirty locally we could do this */
527
Steve French7fc8f4e2009-02-23 20:43:11 +0000528 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700531 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400533 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000534 cFYI(1, "cifs_open returned 0x%x", rc);
535 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400536 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
Jeff Layton15886172010-10-15 15:33:59 -0400538
539reopen_success:
540 pCifsFile->netfid = netfid;
541 pCifsFile->invalidHandle = false;
542 mutex_unlock(&pCifsFile->fh_mutex);
543 pCifsInode = CIFS_I(inode);
544
545 if (can_flush) {
546 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400547 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400548
Jeff Layton15886172010-10-15 15:33:59 -0400549 if (tcon->unix_ext)
550 rc = cifs_get_inode_info_unix(&inode,
551 full_path, inode->i_sb, xid);
552 else
553 rc = cifs_get_inode_info(&inode,
554 full_path, NULL, inode->i_sb,
555 xid, NULL);
556 } /* else we are writing out data to server already
557 and could deadlock if we tried to flush data, and
558 since we do not know if we have data that would
559 invalidate the current end of file on the server
560 we can not go to the server to get the new inod
561 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300562
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300563 cifs_set_oplock_level(pCifsInode, oplock);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300564
Jeff Layton15886172010-10-15 15:33:59 -0400565 cifs_relock_file(pCifsFile);
566
567reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 kfree(full_path);
569 FreeXid(xid);
570 return rc;
571}
572
573int cifs_close(struct inode *inode, struct file *file)
574{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000575 cifsFileInfo_put(file->private_data);
576 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Steve Frenchcdff08e2010-10-21 22:46:14 +0000578 /* return code from the ->release op is always ignored */
579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582int cifs_closedir(struct inode *inode, struct file *file)
583{
584 int rc = 0;
585 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700586 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 char *ptmp;
588
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 xid = GetXid();
592
593 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400594 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400597 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000598 if (!pCFileStruct->srch_inf.endOfSearch &&
599 !pCFileStruct->invalidHandle) {
600 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400601 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000603 cFYI(1, "Closing uncompleted readdir with rc %d",
604 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 /* not much we can do if it fails anyway, ignore rc */
606 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000607 } else
Jeff Layton44772882010-10-15 15:34:03 -0400608 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
610 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000611 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000614 cifs_small_buf_release(ptmp);
615 else
616 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400618 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 kfree(file->private_data);
620 file->private_data = NULL;
621 }
622 /* BB can we lock the filestruct while this is going on? */
623 FreeXid(xid);
624 return rc;
625}
626
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000627static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
628 __u64 offset, __u8 lockType)
629{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000630 struct cifsLockInfo *li =
631 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000632 if (li == NULL)
633 return -ENOMEM;
634 li->offset = offset;
635 li->length = len;
636 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000637 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000638 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000639 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000640 return 0;
641}
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
644{
645 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 __u32 numLock = 0;
647 __u32 numUnlock = 0;
648 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000649 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000651 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000652 __u16 netfid;
653 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000654 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 length = 1 + pfLock->fl_end - pfLock->fl_start;
657 rc = -EACCES;
658 xid = GetXid();
659
Joe Perchesb6b38f72010-04-21 03:50:45 +0000660 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000662 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000670 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000671 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 }
673 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "Process suspended by mandatory locking - "
675 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000677 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000678 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000680 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000683 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 numLock = 1;
685 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000686 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000688 /* Check if unlock includes more than
689 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000691 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 lockType |= LOCKING_ANDX_SHARED_LOCK;
693 numLock = 1;
694 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000695 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 numLock = 1;
697 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000698 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 lockType |= LOCKING_ANDX_SHARED_LOCK;
700 numLock = 1;
701 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800704 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400705 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Steve French08547b02006-02-28 22:39:25 +0000706 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Steve French13a6e422008-12-02 17:24:33 +0000708 if ((tcon->ses->capabilities & CAP_UNIX) &&
709 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000710 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000711 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000712 /* BB add code here to normalize offset and length to
713 account for negative length which we can not accept over the
714 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000716 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000717 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000718 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000719 posix_lock_type = CIFS_RDLCK;
720 else
721 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000722 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000723 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000724 posix_lock_type, wait_flag);
725 FreeXid(xid);
726 return rc;
727 }
728
729 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000730 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000731 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000733 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 pfLock->fl_start, 1 /* numUnlock */ ,
735 0 /* numLock */ , lockType,
736 0 /* wait flag */ );
737 pfLock->fl_type = F_UNLCK;
738 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000739 cERROR(1, "Error unlocking previously locked "
740 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 rc = 0;
742
743 } else {
744 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400745 rc = 0;
746
747 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
748 pfLock->fl_type = F_WRLCK;
749 } else {
750 rc = CIFSSMBLock(xid, tcon, netfid, length,
751 pfLock->fl_start, 0, 1,
752 lockType | LOCKING_ANDX_SHARED_LOCK,
753 0 /* wait flag */);
754 if (rc == 0) {
755 rc = CIFSSMBLock(xid, tcon, netfid,
756 length, pfLock->fl_start, 1, 0,
757 lockType |
758 LOCKING_ANDX_SHARED_LOCK,
759 0 /* wait flag */);
760 pfLock->fl_type = F_RDLCK;
761 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000762 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400763 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000764 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400765 rc = 0;
766 } else {
767 pfLock->fl_type = F_WRLCK;
768 rc = 0;
769 }
770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772
773 FreeXid(xid);
774 return rc;
775 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000776
777 if (!numLock && !numUnlock) {
778 /* if no lock or unlock then nothing
779 to do since we do not know what it is */
780 FreeXid(xid);
781 return -EOPNOTSUPP;
782 }
783
784 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000785 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000786 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000787 posix_lock_type = CIFS_RDLCK;
788 else
789 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000790
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000791 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000792 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000793
Steve French13a6e422008-12-02 17:24:33 +0000794 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000795 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000796 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000797 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700798 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799
800 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000801 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000802 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000803 0, numLock, lockType, wait_flag);
804
805 if (rc == 0) {
806 /* For Windows locks we must store them. */
807 rc = store_file_lock(fid, length,
808 pfLock->fl_start, lockType);
809 }
810 } else if (numUnlock) {
811 /* For each stored lock that this unlock overlaps
812 completely, unlock it. */
813 int stored_rc = 0;
814 struct cifsLockInfo *li, *tmp;
815
Steve French6b70c952006-09-21 07:35:29 +0000816 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000817 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000818 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
819 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000820 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000821 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000822 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000823 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000824 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000825 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000826 if (stored_rc)
827 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000828 else {
829 list_del(&li->llist);
830 kfree(li);
831 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000832 }
833 }
Roland Dreier796e5662007-05-03 04:33:45 +0000834 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000835 }
836 }
837
Steve Frenchd634cc12005-08-26 14:42:59 -0500838 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 posix_lock_file_wait(file, pfLock);
840 FreeXid(xid);
841 return rc;
842}
843
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400844/*
845 * Set the timeout on write requests past EOF. For some servers (Windows)
846 * these calls can be very long.
847 *
848 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
849 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
850 * The 10M cutoff is totally arbitrary. A better scheme for this would be
851 * welcome if someone wants to suggest one.
852 *
853 * We may be able to do a better job with this if there were some way to
854 * declare that a file should be sparse.
855 */
856static int
857cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
858{
859 if (offset <= cifsi->server_eof)
860 return CIFS_STD_OP;
861 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
862 return CIFS_VLONG_OP;
863 else
864 return CIFS_LONG_OP;
865}
866
867/* update the file size (if needed) after a write */
868static void
869cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
870 unsigned int bytes_written)
871{
872 loff_t end_of_write = offset + bytes_written;
873
874 if (end_of_write > cifsi->server_eof)
875 cifsi->server_eof = end_of_write;
876}
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878ssize_t cifs_user_write(struct file *file, const char __user *write_data,
879 size_t write_size, loff_t *poffset)
880{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100881 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 int rc = 0;
883 unsigned int bytes_written = 0;
884 unsigned int total_written;
885 struct cifs_sb_info *cifs_sb;
886 struct cifsTconInfo *pTcon;
887 int xid, long_op;
888 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100889 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800891 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Joe Perchesb6b38f72010-04-21 03:50:45 +0000893 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
894 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 if (file->private_data == NULL)
897 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700898
Joe Perchesc21dfb62010-07-12 13:50:14 -0700899 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400900 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000901
Jeff Layton838726c2008-08-28 07:54:59 -0400902 rc = generic_write_checks(file, poffset, &write_size, 0);
903 if (rc)
904 return rc;
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400908 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 for (total_written = 0; write_size > total_written;
910 total_written += bytes_written) {
911 rc = -EAGAIN;
912 while (rc == -EAGAIN) {
913 if (file->private_data == NULL) {
914 /* file has been closed on us */
915 FreeXid(xid);
916 /* if we have gotten here we have written some data
917 and blocked, and the file has been freed on us while
918 we blocked so return what we managed to write */
919 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 /* we could deadlock if we called
923 filemap_fdatawait from here so tell
924 reopen_file not to flush data to server
925 now */
Jeff Layton15886172010-10-15 15:33:59 -0400926 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 if (rc != 0)
928 break;
929 }
930
931 rc = CIFSSMBWrite(xid, pTcon,
932 open_file->netfid,
933 min_t(const int, cifs_sb->wsize,
934 write_size - total_written),
935 *poffset, &bytes_written,
936 NULL, write_data + total_written, long_op);
937 }
938 if (rc || (bytes_written == 0)) {
939 if (total_written)
940 break;
941 else {
942 FreeXid(xid);
943 return rc;
944 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400945 } else {
946 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400948 }
Steve French133672e2007-11-13 22:41:37 +0000949 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 15 seconds is plenty */
951 }
952
Steve Frencha4544342005-08-24 13:59:35 -0700953 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000955/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100956 * inode->i_ctime = inode->i_mtime =
957 * current_fs_time(inode->i_sb);*/
958 if (total_written > 0) {
959 spin_lock(&inode->i_lock);
960 if (*poffset > inode->i_size)
961 i_size_write(inode, *poffset);
962 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100964 mark_inode_dirty_sync(inode);
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 FreeXid(xid);
967 return total_written;
968}
969
Jeff Layton7da4b492010-10-15 15:34:00 -0400970static ssize_t cifs_write(struct cifsFileInfo *open_file,
971 const char *write_data, size_t write_size,
972 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 int rc = 0;
975 unsigned int bytes_written = 0;
976 unsigned int total_written;
977 struct cifs_sb_info *cifs_sb;
978 struct cifsTconInfo *pTcon;
979 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -0400980 struct dentry *dentry = open_file->dentry;
981 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Jeff Layton7da4b492010-10-15 15:34:00 -0400983 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Joe Perchesb6b38f72010-04-21 03:50:45 +0000985 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -0400986 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Jeff Layton13cfb732010-09-29 19:51:11 -0400988 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400992 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 for (total_written = 0; write_size > total_written;
994 total_written += bytes_written) {
995 rc = -EAGAIN;
996 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 /* we could deadlock if we called
999 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001000 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001002 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (rc != 0)
1004 break;
1005 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001006 if (experimEnabled || (pTcon->ses->server &&
1007 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001008 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001009 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001010 struct kvec iov[2];
1011 unsigned int len;
1012
Steve French0ae0efa2005-10-10 10:57:19 -07001013 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001014 write_size - total_written);
1015 /* iov[0] is reserved for smb header */
1016 iov[1].iov_base = (char *)write_data +
1017 total_written;
1018 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001019 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001020 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001021 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001022 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001023 } else
Steve French60808232006-04-22 15:53:05 +00001024 rc = CIFSSMBWrite(xid, pTcon,
1025 open_file->netfid,
1026 min_t(const int, cifs_sb->wsize,
1027 write_size - total_written),
1028 *poffset, &bytes_written,
1029 write_data + total_written,
1030 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 }
1032 if (rc || (bytes_written == 0)) {
1033 if (total_written)
1034 break;
1035 else {
1036 FreeXid(xid);
1037 return rc;
1038 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001039 } else {
1040 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001042 }
Steve French133672e2007-11-13 22:41:37 +00001043 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 15 seconds is plenty */
1045 }
1046
Steve Frencha4544342005-08-24 13:59:35 -07001047 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Jeff Layton7da4b492010-10-15 15:34:00 -04001049 if (total_written > 0) {
1050 spin_lock(&dentry->d_inode->i_lock);
1051 if (*poffset > dentry->d_inode->i_size)
1052 i_size_write(dentry->d_inode, *poffset);
1053 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001055 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 FreeXid(xid);
1057 return total_written;
1058}
1059
Jeff Layton6508d902010-09-29 19:51:11 -04001060struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1061 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001062{
1063 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001064 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1065
1066 /* only filter by fsuid on multiuser mounts */
1067 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1068 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001069
Jeff Layton44772882010-10-15 15:34:03 -04001070 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001071 /* we could simply get the first_list_entry since write-only entries
1072 are always at the end of the list but since the first entry might
1073 have a close pending, we go through the whole list */
1074 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001075 if (fsuid_only && open_file->uid != current_fsuid())
1076 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001077 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001078 if (!open_file->invalidHandle) {
1079 /* found a good file */
1080 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001081 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001082 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001083 return open_file;
1084 } /* else might as well continue, and look for
1085 another, or simply have the caller reopen it
1086 again rather than trying to fix this handle */
1087 } else /* write only file */
1088 break; /* write only files are last so must be done */
1089 }
Jeff Layton44772882010-10-15 15:34:03 -04001090 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001091 return NULL;
1092}
Steve French630f3f0c2007-10-25 21:17:17 +00001093
Jeff Layton6508d902010-09-29 19:51:11 -04001094struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1095 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001096{
1097 struct cifsFileInfo *open_file;
Jeff Laytond3892292010-11-02 16:22:50 -04001098 struct cifs_sb_info *cifs_sb;
Jeff Layton2846d382008-09-22 21:33:33 -04001099 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001100 int rc;
Steve French6148a742005-10-05 12:23:19 -07001101
Steve French60808232006-04-22 15:53:05 +00001102 /* Having a null inode here (because mapping->host was set to zero by
1103 the VFS or MM) should not happen but we had reports of on oops (due to
1104 it being zero) during stress testcases so we need to check for it */
1105
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001106 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001107 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001108 dump_stack();
1109 return NULL;
1110 }
1111
Jeff Laytond3892292010-11-02 16:22:50 -04001112 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1113
Jeff Layton6508d902010-09-29 19:51:11 -04001114 /* only filter by fsuid on multiuser mounts */
1115 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1116 fsuid_only = false;
1117
Jeff Layton44772882010-10-15 15:34:03 -04001118 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001119refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001120 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001121 if (!any_available && open_file->pid != current->tgid)
1122 continue;
1123 if (fsuid_only && open_file->uid != current_fsuid())
1124 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001125 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001126 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001127
1128 if (!open_file->invalidHandle) {
1129 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001130 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001131 return open_file;
1132 }
Steve French8840dee2007-11-16 23:05:52 +00001133
Jeff Layton44772882010-10-15 15:34:03 -04001134 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001135
Steve French9b22b0b2007-10-02 01:11:08 +00001136 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001137 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001138 if (!rc)
1139 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001140
Steve Frenchcdff08e2010-10-21 22:46:14 +00001141 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001142 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001143 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001144
Steve Frenchcdff08e2010-10-21 22:46:14 +00001145 spin_lock(&cifs_file_list_lock);
1146
Steve French9b22b0b2007-10-02 01:11:08 +00001147 /* else we simply continue to the next entry. Thus
1148 we do not loop on reopen errors. If we
1149 can not reopen the file, for example if we
1150 reconnected to a server with another client
1151 racing to delete or lock the file we would not
1152 make progress if we restarted before the beginning
1153 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001154 }
1155 }
Jeff Layton2846d382008-09-22 21:33:33 -04001156 /* couldn't find useable FH with same pid, try any available */
1157 if (!any_available) {
1158 any_available = true;
1159 goto refind_writable;
1160 }
Jeff Layton44772882010-10-15 15:34:03 -04001161 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001162 return NULL;
1163}
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1166{
1167 struct address_space *mapping = page->mapping;
1168 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1169 char *write_data;
1170 int rc = -EFAULT;
1171 int bytes_written = 0;
1172 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001174 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 if (!mapping || !mapping->host)
1177 return -EFAULT;
1178
1179 inode = page->mapping->host;
1180 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 offset += (loff_t)from;
1183 write_data = kmap(page);
1184 write_data += from;
1185
1186 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1187 kunmap(page);
1188 return -EIO;
1189 }
1190
1191 /* racing with truncate? */
1192 if (offset > mapping->host->i_size) {
1193 kunmap(page);
1194 return 0; /* don't care */
1195 }
1196
1197 /* check to make sure that we are not extending the file */
1198 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001199 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
Jeff Layton6508d902010-09-29 19:51:11 -04001201 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001202 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001203 bytes_written = cifs_write(open_file, write_data,
1204 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001205 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001207 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001208 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001209 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001210 else if (bytes_written < 0)
1211 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001212 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001213 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 rc = -EIO;
1215 }
1216
1217 kunmap(page);
1218 return rc;
1219}
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001222 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
Steve French37c0eb42005-10-05 14:50:29 -07001224 unsigned int bytes_to_write;
1225 unsigned int bytes_written;
1226 struct cifs_sb_info *cifs_sb;
1227 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001228 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001229 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001230 int range_whole = 0;
1231 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001232 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001233 int n_iov = 0;
1234 pgoff_t next;
1235 int nr_pages;
1236 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001237 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001238 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001239 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001240 struct page *page;
1241 struct pagevec pvec;
1242 int rc = 0;
1243 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001244 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Steve French37c0eb42005-10-05 14:50:29 -07001246 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001247
Steve French37c0eb42005-10-05 14:50:29 -07001248 /*
1249 * If wsize is smaller that the page cache size, default to writing
1250 * one page at a time via cifs_writepage
1251 */
1252 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1253 return generic_writepages(mapping, wbc);
1254
Steve French9a0c8232007-02-02 04:21:57 +00001255 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001256 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001257 return generic_writepages(mapping, wbc);
1258
Steve French37c0eb42005-10-05 14:50:29 -07001259 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001260 * if there's no open file, then this is likely to fail too,
1261 * but it'll at least handle the return. Maybe it should be
1262 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001263 */
Jeff Layton6508d902010-09-29 19:51:11 -04001264 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001265 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001266 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001267 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001268 }
1269
Jeff Layton13cfb732010-09-29 19:51:11 -04001270 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001271 if (!experimEnabled && tcon->ses->server->secMode &
1272 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1273 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001274 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001275 return generic_writepages(mapping, wbc);
1276 }
1277 cifsFileInfo_put(open_file);
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 xid = GetXid();
1280
Steve French37c0eb42005-10-05 14:50:29 -07001281 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001282 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001283 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001284 end = -1;
1285 } else {
1286 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1287 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1288 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1289 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001290 scanned = 1;
1291 }
1292retry:
1293 while (!done && (index <= end) &&
1294 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1295 PAGECACHE_TAG_DIRTY,
1296 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1297 int first;
1298 unsigned int i;
1299
Steve French37c0eb42005-10-05 14:50:29 -07001300 first = -1;
1301 next = 0;
1302 n_iov = 0;
1303 bytes_to_write = 0;
1304
1305 for (i = 0; i < nr_pages; i++) {
1306 page = pvec.pages[i];
1307 /*
1308 * At this point we hold neither mapping->tree_lock nor
1309 * lock on the page itself: the page may be truncated or
1310 * invalidated (changing page->mapping to NULL), or even
1311 * swizzled back from swapper_space to tmpfs file
1312 * mapping
1313 */
1314
1315 if (first < 0)
1316 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001317 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001318 break;
1319
1320 if (unlikely(page->mapping != mapping)) {
1321 unlock_page(page);
1322 break;
1323 }
1324
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001325 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001326 done = 1;
1327 unlock_page(page);
1328 break;
1329 }
1330
1331 if (next && (page->index != next)) {
1332 /* Not next consecutive page */
1333 unlock_page(page);
1334 break;
1335 }
1336
1337 if (wbc->sync_mode != WB_SYNC_NONE)
1338 wait_on_page_writeback(page);
1339
1340 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001341 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001342 unlock_page(page);
1343 break;
1344 }
Steve French84d2f072005-10-12 15:32:05 -07001345
Linus Torvaldscb876f42006-12-23 16:19:07 -08001346 /*
1347 * This actually clears the dirty bit in the radix tree.
1348 * See cifs_writepage() for more commentary.
1349 */
1350 set_page_writeback(page);
1351
Steve French84d2f072005-10-12 15:32:05 -07001352 if (page_offset(page) >= mapping->host->i_size) {
1353 done = 1;
1354 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001355 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001356 break;
1357 }
1358
Steve French37c0eb42005-10-05 14:50:29 -07001359 /*
1360 * BB can we get rid of this? pages are held by pvec
1361 */
1362 page_cache_get(page);
1363
Steve French84d2f072005-10-12 15:32:05 -07001364 len = min(mapping->host->i_size - page_offset(page),
1365 (loff_t)PAGE_CACHE_SIZE);
1366
Steve French37c0eb42005-10-05 14:50:29 -07001367 /* reserve iov[0] for the smb header */
1368 n_iov++;
1369 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001370 iov[n_iov].iov_len = len;
1371 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001372
1373 if (first < 0) {
1374 first = i;
1375 offset = page_offset(page);
1376 }
1377 next = page->index + 1;
1378 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1379 break;
1380 }
1381 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001382 open_file = find_writable_file(CIFS_I(mapping->host),
1383 false);
Steve French23e7dd72005-10-20 13:44:56 -07001384 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001385 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001386 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001387 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001388 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001389 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001390 bytes_to_write, offset,
1391 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001392 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001393 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001394 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001395 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001396
1397 if (rc || bytes_written < bytes_to_write) {
1398 cERROR(1, "Write2 ret %d, wrote %d",
1399 rc, bytes_written);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001400 mapping_set_error(mapping, rc);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001401 } else {
1402 cifs_stats_bytes_written(tcon, bytes_written);
1403 }
1404
Steve French37c0eb42005-10-05 14:50:29 -07001405 for (i = 0; i < n_iov; i++) {
1406 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001407 /* Should we also set page error on
1408 success rc but too little data written? */
1409 /* BB investigate retry logic on temporary
1410 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001411 when page marked as error */
1412 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001413 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001414 kunmap(page);
1415 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001416 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001417 page_cache_release(page);
1418 }
1419 if ((wbc->nr_to_write -= n_iov) <= 0)
1420 done = 1;
1421 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001422 } else
1423 /* Need to re-find the pages we skipped */
1424 index = pvec.pages[0]->index + 1;
1425
Steve French37c0eb42005-10-05 14:50:29 -07001426 pagevec_release(&pvec);
1427 }
1428 if (!scanned && !done) {
1429 /*
1430 * We hit the last page and there is more work to be done: wrap
1431 * back to the start of the file
1432 */
1433 scanned = 1;
1434 index = 0;
1435 goto retry;
1436 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001437 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001438 mapping->writeback_index = index;
1439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001441 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 return rc;
1443}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001445static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446{
1447 int rc = -EFAULT;
1448 int xid;
1449
1450 xid = GetXid();
1451/* BB add check for wbc flags */
1452 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001453 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001454 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001455
1456 /*
1457 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1458 *
1459 * A writepage() implementation always needs to do either this,
1460 * or re-dirty the page with "redirty_page_for_writepage()" in
1461 * the case of a failure.
1462 *
1463 * Just unlocking the page will cause the radix tree tag-bits
1464 * to fail to update with the state of the page correctly.
1465 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001466 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1468 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1469 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001470 end_page_writeback(page);
1471 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 FreeXid(xid);
1473 return rc;
1474}
1475
Nick Piggind9414772008-09-24 11:32:59 -04001476static int cifs_write_end(struct file *file, struct address_space *mapping,
1477 loff_t pos, unsigned len, unsigned copied,
1478 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479{
Nick Piggind9414772008-09-24 11:32:59 -04001480 int rc;
1481 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Joe Perchesb6b38f72010-04-21 03:50:45 +00001483 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1484 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001485
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001486 if (PageChecked(page)) {
1487 if (copied == len)
1488 SetPageUptodate(page);
1489 ClearPageChecked(page);
1490 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001491 SetPageUptodate(page);
1492
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001494 char *page_data;
1495 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1496 int xid;
1497
1498 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 /* this is probably better than directly calling
1500 partialpage_write since in this function the file handle is
1501 known which we might as well leverage */
1502 /* BB check if anything else missing out of ppw
1503 such as updating last write time */
1504 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001505 rc = cifs_write(file->private_data, page_data + offset,
1506 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001507 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001509
1510 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001511 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001512 rc = copied;
1513 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 set_page_dirty(page);
1515 }
1516
Nick Piggind9414772008-09-24 11:32:59 -04001517 if (rc > 0) {
1518 spin_lock(&inode->i_lock);
1519 if (pos > inode->i_size)
1520 i_size_write(inode, pos);
1521 spin_unlock(&inode->i_lock);
1522 }
1523
1524 unlock_page(page);
1525 page_cache_release(page);
1526
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 return rc;
1528}
1529
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001530int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 int xid;
1533 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001534 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001535 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001536 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 xid = GetXid();
1539
Joe Perchesb6b38f72010-04-21 03:50:45 +00001540 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001541 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001542
Jeff Laytoncea21802007-11-20 23:19:03 +00001543 rc = filemap_write_and_wait(inode->i_mapping);
1544 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001545 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1546
Jeff Layton13cfb732010-09-29 19:51:11 -04001547 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001548 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001549 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001550 }
Steve Frenchb298f222009-02-21 21:17:43 +00001551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 FreeXid(xid);
1553 return rc;
1554}
1555
NeilBrown3978d7172006-03-26 01:37:17 -08001556/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
1558 struct address_space *mapping;
1559 struct inode *inode;
1560 unsigned long index = page->index;
1561 unsigned int rpages = 0;
1562 int rc = 0;
1563
Steve Frenchf19159d2010-04-21 04:12:10 +00001564 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 mapping = page->mapping;
1566 if (!mapping)
1567 return 0;
1568 inode = mapping->host;
1569 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001570 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001572/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1574
Joe Perchesb6b38f72010-04-21 03:50:45 +00001575/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
NeilBrown3978d7172006-03-26 01:37:17 -08001577#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (rc < 0)
1579 return rc;
1580 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001581#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582} */
1583
1584/*
1585 * As file closes, flush all cached write data for this inode checking
1586 * for write behind errors.
1587 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001588int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001590 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 int rc = 0;
1592
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001593 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001594 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001595
Joe Perchesb6b38f72010-04-21 03:50:45 +00001596 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 return rc;
1599}
1600
1601ssize_t cifs_user_read(struct file *file, char __user *read_data,
1602 size_t read_size, loff_t *poffset)
1603{
1604 int rc = -EACCES;
1605 unsigned int bytes_read = 0;
1606 unsigned int total_read = 0;
1607 unsigned int current_read_size;
1608 struct cifs_sb_info *cifs_sb;
1609 struct cifsTconInfo *pTcon;
1610 int xid;
1611 struct cifsFileInfo *open_file;
1612 char *smb_read_data;
1613 char __user *current_offset;
1614 struct smb_com_read_rsp *pSMBr;
1615
1616 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001617 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301620 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301622 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001624 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001625 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Steve Frenchad7a2922008-02-07 23:25:02 +00001627 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001628 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001629
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 for (total_read = 0, current_offset = read_data;
1631 read_size > total_read;
1632 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001633 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 cifs_sb->rsize);
1635 rc = -EAGAIN;
1636 smb_read_data = NULL;
1637 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001638 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001639 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001640 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 if (rc != 0)
1642 break;
1643 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001644 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001645 open_file->netfid,
1646 current_read_size, *poffset,
1647 &bytes_read, &smb_read_data,
1648 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001651 if (copy_to_user(current_offset,
1652 smb_read_data +
1653 4 /* RFC1001 length field */ +
1654 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001655 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001656 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001657
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001658 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001659 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001660 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001661 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 smb_read_data = NULL;
1663 }
1664 }
1665 if (rc || (bytes_read == 0)) {
1666 if (total_read) {
1667 break;
1668 } else {
1669 FreeXid(xid);
1670 return rc;
1671 }
1672 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001673 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 *poffset += bytes_read;
1675 }
1676 }
1677 FreeXid(xid);
1678 return total_read;
1679}
1680
1681
1682static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1683 loff_t *poffset)
1684{
1685 int rc = -EACCES;
1686 unsigned int bytes_read = 0;
1687 unsigned int total_read;
1688 unsigned int current_read_size;
1689 struct cifs_sb_info *cifs_sb;
1690 struct cifsTconInfo *pTcon;
1691 int xid;
1692 char *current_offset;
1693 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001694 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001697 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301700 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301702 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001704 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001705 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
1707 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001708 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001710 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 read_size > total_read;
1712 total_read += bytes_read, current_offset += bytes_read) {
1713 current_read_size = min_t(const int, read_size - total_read,
1714 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001715 /* For windows me and 9x we do not want to request more
1716 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001717 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001718 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1719 current_read_size = min_t(const int, current_read_size,
1720 pTcon->ses->server->maxBuf - 128);
1721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 rc = -EAGAIN;
1723 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001724 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001725 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (rc != 0)
1727 break;
1728 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001729 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001730 open_file->netfid,
1731 current_read_size, *poffset,
1732 &bytes_read, &current_offset,
1733 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
1735 if (rc || (bytes_read == 0)) {
1736 if (total_read) {
1737 break;
1738 } else {
1739 FreeXid(xid);
1740 return rc;
1741 }
1742 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001743 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 *poffset += bytes_read;
1745 }
1746 }
1747 FreeXid(xid);
1748 return total_read;
1749}
1750
1751int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1752{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 int rc, xid;
1754
1755 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001756 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001758 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 FreeXid(xid);
1760 return rc;
1761 }
1762 rc = generic_file_mmap(file, vma);
1763 FreeXid(xid);
1764 return rc;
1765}
1766
1767
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001769 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
1771 struct page *page;
1772 char *target;
1773
1774 while (bytes_read > 0) {
1775 if (list_empty(pages))
1776 break;
1777
1778 page = list_entry(pages->prev, struct page, lru);
1779 list_del(&page->lru);
1780
Nick Piggin315e9952010-04-21 03:18:28 +00001781 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 GFP_KERNEL)) {
1783 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001784 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001785 data += PAGE_CACHE_SIZE;
1786 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 continue;
1788 }
Jeff Layton06b43672010-06-01 10:54:45 -04001789 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001791 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793 if (PAGE_CACHE_SIZE > bytes_read) {
1794 memcpy(target, data, bytes_read);
1795 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001796 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 PAGE_CACHE_SIZE - bytes_read);
1798 bytes_read = 0;
1799 } else {
1800 memcpy(target, data, PAGE_CACHE_SIZE);
1801 bytes_read -= PAGE_CACHE_SIZE;
1802 }
1803 kunmap_atomic(target, KM_USER0);
1804
1805 flush_dcache_page(page);
1806 SetPageUptodate(page);
1807 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301809
1810 /* add page to FS-Cache */
1811 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 }
1813 return;
1814}
1815
1816static int cifs_readpages(struct file *file, struct address_space *mapping,
1817 struct list_head *page_list, unsigned num_pages)
1818{
1819 int rc = -EACCES;
1820 int xid;
1821 loff_t offset;
1822 struct page *page;
1823 struct cifs_sb_info *cifs_sb;
1824 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001825 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001826 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 char *smb_read_data = NULL;
1828 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001830 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
1832 xid = GetXid();
1833 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301834 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301836 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001838 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001839 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001840 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001841
Suresh Jayaraman56698232010-07-05 18:13:25 +05301842 /*
1843 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1844 * immediately if the cookie is negative
1845 */
1846 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1847 &num_pages);
1848 if (rc == 0)
1849 goto read_complete;
1850
Steve Frenchf19159d2010-04-21 04:12:10 +00001851 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 for (i = 0; i < num_pages; ) {
1853 unsigned contig_pages;
1854 struct page *tmp_page;
1855 unsigned long expected_index;
1856
1857 if (list_empty(page_list))
1858 break;
1859
1860 page = list_entry(page_list->prev, struct page, lru);
1861 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1862
1863 /* count adjacent pages that we will read into */
1864 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001865 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001867 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (tmp_page->index == expected_index) {
1869 contig_pages++;
1870 expected_index++;
1871 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
1874 if (contig_pages + i > num_pages)
1875 contig_pages = num_pages - i;
1876
1877 /* for reads over a certain size could initiate async
1878 read ahead */
1879
1880 read_size = contig_pages * PAGE_CACHE_SIZE;
1881 /* Read size needs to be in multiples of one page */
1882 read_size = min_t(const unsigned int, read_size,
1883 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001884 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1885 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 rc = -EAGAIN;
1887 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001888 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001889 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (rc != 0)
1891 break;
1892 }
1893
Steve Frenchbfa0d752005-08-31 21:50:37 -07001894 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001895 open_file->netfid,
1896 read_size, offset,
1897 &bytes_read, &smb_read_data,
1898 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001899 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001900 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001903 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001904 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001905 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 smb_read_data = NULL;
1907 }
1908 }
1909 }
1910 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001911 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 break;
1913 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001914 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1916 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1917 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001918 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001921 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001922 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 i++; /* account for partial page */
1924
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001925 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001927 /* BB do we need to verify this common case ?
1928 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 we will hit it on next read */
1930
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001931 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
1933 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001934 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001935 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001936 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001937 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 break;
1940 }
1941 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001942 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001943 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001944 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001945 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 smb_read_data = NULL;
1947 }
1948 bytes_read = 0;
1949 }
1950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951/* need to free smb_read_data buf before exit */
1952 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001953 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001954 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001955 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001956 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
Suresh Jayaraman56698232010-07-05 18:13:25 +05301960read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 FreeXid(xid);
1962 return rc;
1963}
1964
1965static int cifs_readpage_worker(struct file *file, struct page *page,
1966 loff_t *poffset)
1967{
1968 char *read_data;
1969 int rc;
1970
Suresh Jayaraman56698232010-07-05 18:13:25 +05301971 /* Is the page cached? */
1972 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
1973 if (rc == 0)
1974 goto read_complete;
1975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 page_cache_get(page);
1977 read_data = kmap(page);
1978 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001979
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (rc < 0)
1983 goto io_error;
1984 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001985 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001986
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001987 file->f_path.dentry->d_inode->i_atime =
1988 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 if (PAGE_CACHE_SIZE > rc)
1991 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1992
1993 flush_dcache_page(page);
1994 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301995
1996 /* send this page to the cache */
1997 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002002 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302004
2005read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 return rc;
2007}
2008
2009static int cifs_readpage(struct file *file, struct page *page)
2010{
2011 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2012 int rc = -EACCES;
2013 int xid;
2014
2015 xid = GetXid();
2016
2017 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302018 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302020 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022
Joe Perchesb6b38f72010-04-21 03:50:45 +00002023 cFYI(1, "readpage %p at offset %d 0x%x\n",
2024 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 rc = cifs_readpage_worker(file, page, &offset);
2027
2028 unlock_page(page);
2029
2030 FreeXid(xid);
2031 return rc;
2032}
2033
Steve Frencha403a0a2007-07-26 15:54:16 +00002034static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2035{
2036 struct cifsFileInfo *open_file;
2037
Jeff Layton44772882010-10-15 15:34:03 -04002038 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002039 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002040 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002041 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002042 return 1;
2043 }
2044 }
Jeff Layton44772882010-10-15 15:34:03 -04002045 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002046 return 0;
2047}
2048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049/* We do not want to update the file size from server for inodes
2050 open for write - to avoid races with writepage extending
2051 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 but this is tricky to do without racing with writebehind
2054 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002055bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056{
Steve Frencha403a0a2007-07-26 15:54:16 +00002057 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002058 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002059
Steve Frencha403a0a2007-07-26 15:54:16 +00002060 if (is_inode_writable(cifsInode)) {
2061 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002062 struct cifs_sb_info *cifs_sb;
2063
Steve Frenchc32a0b62006-01-12 14:41:28 -08002064 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002065 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002067 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002068 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002069 }
2070
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002071 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002072 return true;
Steve French7ba52632007-02-08 18:14:13 +00002073
Steve French4b18f2a2008-04-29 00:06:05 +00002074 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002075 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002076 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077}
2078
Nick Piggind9414772008-09-24 11:32:59 -04002079static int cifs_write_begin(struct file *file, struct address_space *mapping,
2080 loff_t pos, unsigned len, unsigned flags,
2081 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
Nick Piggind9414772008-09-24 11:32:59 -04002083 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2084 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002085 loff_t page_start = pos & PAGE_MASK;
2086 loff_t i_size;
2087 struct page *page;
2088 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Joe Perchesb6b38f72010-04-21 03:50:45 +00002090 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002091
Nick Piggin54566b22009-01-04 12:00:53 -08002092 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002093 if (!page) {
2094 rc = -ENOMEM;
2095 goto out;
2096 }
Nick Piggind9414772008-09-24 11:32:59 -04002097
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002098 if (PageUptodate(page))
2099 goto out;
Steve French8a236262007-03-06 00:31:00 +00002100
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002101 /*
2102 * If we write a full page it will be up to date, no need to read from
2103 * the server. If the write is short, we'll end up doing a sync write
2104 * instead.
2105 */
2106 if (len == PAGE_CACHE_SIZE)
2107 goto out;
2108
2109 /*
2110 * optimize away the read when we have an oplock, and we're not
2111 * expecting to use any of the data we'd be reading in. That
2112 * is, when the page lies beyond the EOF, or straddles the EOF
2113 * and the write will cover all of the existing data.
2114 */
2115 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2116 i_size = i_size_read(mapping->host);
2117 if (page_start >= i_size ||
2118 (offset == 0 && (pos + len) >= i_size)) {
2119 zero_user_segments(page, 0, offset,
2120 offset + len,
2121 PAGE_CACHE_SIZE);
2122 /*
2123 * PageChecked means that the parts of the page
2124 * to which we're not writing are considered up
2125 * to date. Once the data is copied to the
2126 * page, it can be set uptodate.
2127 */
2128 SetPageChecked(page);
2129 goto out;
2130 }
2131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Nick Piggind9414772008-09-24 11:32:59 -04002133 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002134 /*
2135 * might as well read a page, it is fast enough. If we get
2136 * an error, we don't need to return it. cifs_write_end will
2137 * do a sync write instead since PG_uptodate isn't set.
2138 */
2139 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002140 } else {
2141 /* we could try using another file handle if there is one -
2142 but how would we lock it to prevent close of that handle
2143 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002144 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002145 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002146out:
2147 *pagep = page;
2148 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149}
2150
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302151static int cifs_release_page(struct page *page, gfp_t gfp)
2152{
2153 if (PagePrivate(page))
2154 return 0;
2155
2156 return cifs_fscache_release_page(page, gfp);
2157}
2158
2159static void cifs_invalidate_page(struct page *page, unsigned long offset)
2160{
2161 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2162
2163 if (offset == 0)
2164 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2165}
2166
Tejun Heo9b646972010-07-20 22:09:02 +02002167void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002168{
2169 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2170 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002171 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002172 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002173 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002174
2175 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002176 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002177 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002178 else
Al Viro8737c932009-12-24 06:47:55 -05002179 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002180 rc = filemap_fdatawrite(inode->i_mapping);
2181 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002182 rc = filemap_fdatawait(inode->i_mapping);
2183 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002184 invalidate_remote_inode(inode);
2185 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002186 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002187 }
2188
2189 /*
2190 * releasing stale oplock after recent reconnect of smb session using
2191 * a now incorrect file handle is not a data integrity issue but do
2192 * not bother sending an oplock release if session to server still is
2193 * disconnected since oplock already released by the server
2194 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002195 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002196 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2197 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002198 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002199 }
Tejun Heo9b646972010-07-20 22:09:02 +02002200
2201 /*
2202 * We might have kicked in before is_valid_oplock_break()
2203 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302204 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002205 */
Jeff Layton44772882010-10-15 15:34:03 -04002206 spin_lock(&cifs_file_list_lock);
2207 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002208
2209 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002210}
2211
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002212/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002213void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002214{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002215 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002216 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002217}
2218
Tejun Heo9b646972010-07-20 22:09:02 +02002219void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002220{
Jeff Laytonebe2e912010-11-10 10:19:10 -05002221 struct super_block *sb = cfile->dentry->d_sb;
2222
Jeff Layton3bc303c2009-09-21 06:47:50 -04002223 cifsFileInfo_put(cfile);
Jeff Laytonebe2e912010-11-10 10:19:10 -05002224 cifs_sb_deactive(sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002225}
2226
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002227const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 .readpage = cifs_readpage,
2229 .readpages = cifs_readpages,
2230 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002231 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002232 .write_begin = cifs_write_begin,
2233 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302235 .releasepage = cifs_release_page,
2236 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 /* .sync_page = cifs_sync_page, */
2238 /* .direct_IO = */
2239};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002240
2241/*
2242 * cifs_readpages requires the server to support a buffer large enough to
2243 * contain the header plus one complete page of data. Otherwise, we need
2244 * to leave cifs_readpages out of the address space operations.
2245 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002246const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002247 .readpage = cifs_readpage,
2248 .writepage = cifs_writepage,
2249 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002250 .write_begin = cifs_write_begin,
2251 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002252 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302253 .releasepage = cifs_release_page,
2254 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002255 /* .sync_page = cifs_sync_page, */
2256 /* .direct_IO = */
2257};