blob: f95ba451173f6e798a11aea103932d4bbb097198 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 __u16 netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 xid = GetXid();
346
347 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400348 tlink = cifs_sb_tlink(cifs_sb);
349 if (IS_ERR(tlink)) {
350 FreeXid(xid);
351 return PTR_ERR(tlink);
352 }
353 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Steve Frencha6ce4932009-04-09 01:14:32 +0000355 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800357 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530359 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400360 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
362
Joe Perchesb6b38f72010-04-21 03:50:45 +0000363 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
364 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000365
366 if (oplockEnabled)
367 oplock = REQ_OPLOCK;
368 else
369 oplock = 0;
370
Steve French64cc2c62009-03-04 19:54:08 +0000371 if (!tcon->broken_posix_open && tcon->unix_ext &&
372 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000373 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
374 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000375 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400376 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000377 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400378 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000379 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000380 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400381
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400382 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
383 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400384 if (pCifsFile == NULL) {
385 CIFSSMBClose(xid, tcon, netfid);
386 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400387 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530388
389 cifs_fscache_set_inode_cookie(inode, file);
390
Steve French276a74a2009-03-03 18:00:34 +0000391 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000392 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
393 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000394 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000395 " unexpected error on SMB posix open"
396 ", disabling posix open support."
397 " Check if server update available.",
398 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000400 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000401 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
402 (rc != -EOPNOTSUPP)) /* path not found or net err */
403 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000404 /* else fallthrough to retry open the old way on network i/o
405 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000406 }
407
Pavel Shilovskyeeb910a2010-11-25 15:12:39 +0300408 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, file->f_flags,
409 &oplock, &netfid, xid);
410 if (rc)
Jeff Layton47c78b72010-06-16 13:40:17 -0400411 goto out;
412
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400413 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400414 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 rc = -ENOMEM;
416 goto out;
417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530419 cifs_fscache_set_inode_cookie(inode, file);
420
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000421 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 /* time to set mode which we can not set earlier due to
423 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000424 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400425 struct cifs_unix_set_info_args args = {
426 .mode = inode->i_mode,
427 .uid = NO_CHANGE_64,
428 .gid = NO_CHANGE_64,
429 .ctime = NO_CHANGE_64,
430 .atime = NO_CHANGE_64,
431 .mtime = NO_CHANGE_64,
432 .device = 0,
433 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400434 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
435 cifs_sb->local_nls,
436 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700437 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
439 }
440
441out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 kfree(full_path);
443 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400444 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return rc;
446}
447
Adrian Bunk04187262006-06-30 18:23:04 +0200448/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449/* to server was lost */
450static int cifs_relock_file(struct cifsFileInfo *cifsFile)
451{
452 int rc = 0;
453
454/* BB list all locks open on this file and relock */
455
456 return rc;
457}
458
Jeff Layton15886172010-10-15 15:33:59 -0400459static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
461 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400462 int xid;
463 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000465 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000467 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 char *full_path = NULL;
469 int desiredAccess;
470 int disposition = FILE_OPEN;
471 __u16 netfid;
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400474 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000475 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400476 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530477 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530479 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481
Jeff Layton15886172010-10-15 15:33:59 -0400482 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400484 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486/* can not grab rename sem here because various ops, including
487 those that already have the rename sem can end up causing writepage
488 to get called and if the server was down that means we end up here,
489 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400490 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000492 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400493 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000495 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
497
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400499 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 if (oplockEnabled)
502 oplock = REQ_OPLOCK;
503 else
Steve French4b18f2a2008-04-29 00:06:05 +0000504 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Steve French7fc8f4e2009-02-23 20:43:11 +0000506 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
507 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
508 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400509
510 /*
511 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
512 * original open. Must mask them off for a reopen.
513 */
Jeff Layton15886172010-10-15 15:33:59 -0400514 unsigned int oflags = pCifsFile->f_flags &
515 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400516
Jeff Layton2422f672010-06-16 13:40:16 -0400517 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000518 cifs_sb->mnt_file_mode /* ignored */,
519 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000520 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000521 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000522 goto reopen_success;
523 }
524 /* fallthrough to retry open the old way on errors, especially
525 in the reconnect path it is important to retry hard */
526 }
527
Jeff Layton15886172010-10-15 15:33:59 -0400528 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000531 by SMBOpen and then calling get_inode_info with returned buf
532 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 and server version of file size can be stale. If we knew for sure
534 that inode was not dirty locally we could do this */
535
Steve French7fc8f4e2009-02-23 20:43:11 +0000536 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000538 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700539 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400541 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cFYI(1, "cifs_open returned 0x%x", rc);
543 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400544 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Jeff Layton15886172010-10-15 15:33:59 -0400546
547reopen_success:
548 pCifsFile->netfid = netfid;
549 pCifsFile->invalidHandle = false;
550 mutex_unlock(&pCifsFile->fh_mutex);
551 pCifsInode = CIFS_I(inode);
552
553 if (can_flush) {
554 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400555 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400556
Jeff Layton15886172010-10-15 15:33:59 -0400557 if (tcon->unix_ext)
558 rc = cifs_get_inode_info_unix(&inode,
559 full_path, inode->i_sb, xid);
560 else
561 rc = cifs_get_inode_info(&inode,
562 full_path, NULL, inode->i_sb,
563 xid, NULL);
564 } /* else we are writing out data to server already
565 and could deadlock if we tried to flush data, and
566 since we do not know if we have data that would
567 invalidate the current end of file on the server
568 we can not go to the server to get the new inod
569 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300570
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300571 cifs_set_oplock_level(pCifsInode, oplock);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300572
Jeff Layton15886172010-10-15 15:33:59 -0400573 cifs_relock_file(pCifsFile);
574
575reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 kfree(full_path);
577 FreeXid(xid);
578 return rc;
579}
580
581int cifs_close(struct inode *inode, struct file *file)
582{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000583 cifsFileInfo_put(file->private_data);
584 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Steve Frenchcdff08e2010-10-21 22:46:14 +0000586 /* return code from the ->release op is always ignored */
587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588}
589
590int cifs_closedir(struct inode *inode, struct file *file)
591{
592 int rc = 0;
593 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700594 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 char *ptmp;
596
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 xid = GetXid();
600
601 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400602 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Joe Perchesb6b38f72010-04-21 03:50:45 +0000604 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400605 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000606 if (!pCFileStruct->srch_inf.endOfSearch &&
607 !pCFileStruct->invalidHandle) {
608 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400609 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000611 cFYI(1, "Closing uncompleted readdir with rc %d",
612 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 /* not much we can do if it fails anyway, ignore rc */
614 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000615 } else
Jeff Layton44772882010-10-15 15:34:03 -0400616 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
618 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000619 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000621 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000622 cifs_small_buf_release(ptmp);
623 else
624 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400626 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 kfree(file->private_data);
628 file->private_data = NULL;
629 }
630 /* BB can we lock the filestruct while this is going on? */
631 FreeXid(xid);
632 return rc;
633}
634
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000635static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
636 __u64 offset, __u8 lockType)
637{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000638 struct cifsLockInfo *li =
639 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000640 if (li == NULL)
641 return -ENOMEM;
642 li->offset = offset;
643 li->length = len;
644 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000645 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000646 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000647 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000648 return 0;
649}
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
652{
653 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 __u32 numLock = 0;
655 __u32 numUnlock = 0;
656 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000657 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000659 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000660 __u16 netfid;
661 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000662 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 length = 1 + pfLock->fl_end - pfLock->fl_start;
665 rc = -EACCES;
666 xid = GetXid();
667
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000670 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000671 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000678 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000679 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000682 cFYI(1, "Process suspended by mandatory locking - "
683 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000685 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000686 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000688 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000691 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 numLock = 1;
693 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000694 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000696 /* Check if unlock includes more than
697 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000699 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 lockType |= LOCKING_ANDX_SHARED_LOCK;
701 numLock = 1;
702 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000703 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 numLock = 1;
705 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000706 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 lockType |= LOCKING_ANDX_SHARED_LOCK;
708 numLock = 1;
709 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000710 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800712 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400713 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Steve French08547b02006-02-28 22:39:25 +0000714 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Steve French13a6e422008-12-02 17:24:33 +0000716 if ((tcon->ses->capabilities & CAP_UNIX) &&
717 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000718 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000719 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000720 /* BB add code here to normalize offset and length to
721 account for negative length which we can not accept over the
722 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000724 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000725 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000726 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000727 posix_lock_type = CIFS_RDLCK;
728 else
729 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000730 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000731 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000732 posix_lock_type, wait_flag);
733 FreeXid(xid);
734 return rc;
735 }
736
737 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000738 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000739 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000741 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 pfLock->fl_start, 1 /* numUnlock */ ,
743 0 /* numLock */ , lockType,
744 0 /* wait flag */ );
745 pfLock->fl_type = F_UNLCK;
746 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cERROR(1, "Error unlocking previously locked "
748 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 rc = 0;
750
751 } else {
752 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400753 rc = 0;
754
755 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
756 pfLock->fl_type = F_WRLCK;
757 } else {
758 rc = CIFSSMBLock(xid, tcon, netfid, length,
759 pfLock->fl_start, 0, 1,
760 lockType | LOCKING_ANDX_SHARED_LOCK,
761 0 /* wait flag */);
762 if (rc == 0) {
763 rc = CIFSSMBLock(xid, tcon, netfid,
764 length, pfLock->fl_start, 1, 0,
765 lockType |
766 LOCKING_ANDX_SHARED_LOCK,
767 0 /* wait flag */);
768 pfLock->fl_type = F_RDLCK;
769 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000770 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400771 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000772 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400773 rc = 0;
774 } else {
775 pfLock->fl_type = F_WRLCK;
776 rc = 0;
777 }
778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780
781 FreeXid(xid);
782 return rc;
783 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000784
785 if (!numLock && !numUnlock) {
786 /* if no lock or unlock then nothing
787 to do since we do not know what it is */
788 FreeXid(xid);
789 return -EOPNOTSUPP;
790 }
791
792 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000793 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000794 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000795 posix_lock_type = CIFS_RDLCK;
796 else
797 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000798
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000799 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000800 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000801
Steve French13a6e422008-12-02 17:24:33 +0000802 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000803 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000804 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000805 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700806 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000807
808 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000809 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000810 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000811 0, numLock, lockType, wait_flag);
812
813 if (rc == 0) {
814 /* For Windows locks we must store them. */
815 rc = store_file_lock(fid, length,
816 pfLock->fl_start, lockType);
817 }
818 } else if (numUnlock) {
819 /* For each stored lock that this unlock overlaps
820 completely, unlock it. */
821 int stored_rc = 0;
822 struct cifsLockInfo *li, *tmp;
823
Steve French6b70c952006-09-21 07:35:29 +0000824 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000825 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000826 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
827 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000828 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000829 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000830 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000831 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000832 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000833 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000834 if (stored_rc)
835 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000836 else {
837 list_del(&li->llist);
838 kfree(li);
839 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000840 }
841 }
Roland Dreier796e5662007-05-03 04:33:45 +0000842 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000843 }
844 }
845
Steve Frenchd634cc12005-08-26 14:42:59 -0500846 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 posix_lock_file_wait(file, pfLock);
848 FreeXid(xid);
849 return rc;
850}
851
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400852/*
853 * Set the timeout on write requests past EOF. For some servers (Windows)
854 * these calls can be very long.
855 *
856 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
857 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
858 * The 10M cutoff is totally arbitrary. A better scheme for this would be
859 * welcome if someone wants to suggest one.
860 *
861 * We may be able to do a better job with this if there were some way to
862 * declare that a file should be sparse.
863 */
864static int
865cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
866{
867 if (offset <= cifsi->server_eof)
868 return CIFS_STD_OP;
869 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
870 return CIFS_VLONG_OP;
871 else
872 return CIFS_LONG_OP;
873}
874
875/* update the file size (if needed) after a write */
876static void
877cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
878 unsigned int bytes_written)
879{
880 loff_t end_of_write = offset + bytes_written;
881
882 if (end_of_write > cifsi->server_eof)
883 cifsi->server_eof = end_of_write;
884}
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886ssize_t cifs_user_write(struct file *file, const char __user *write_data,
887 size_t write_size, loff_t *poffset)
888{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100889 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 int rc = 0;
891 unsigned int bytes_written = 0;
892 unsigned int total_written;
893 struct cifs_sb_info *cifs_sb;
894 struct cifsTconInfo *pTcon;
895 int xid, long_op;
896 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100897 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800899 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Joe Perchesb6b38f72010-04-21 03:50:45 +0000901 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
902 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 if (file->private_data == NULL)
905 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700906
Joe Perchesc21dfb62010-07-12 13:50:14 -0700907 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400908 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000909
Jeff Layton838726c2008-08-28 07:54:59 -0400910 rc = generic_write_checks(file, poffset, &write_size, 0);
911 if (rc)
912 return rc;
913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400916 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 for (total_written = 0; write_size > total_written;
918 total_written += bytes_written) {
919 rc = -EAGAIN;
920 while (rc == -EAGAIN) {
921 if (file->private_data == NULL) {
922 /* file has been closed on us */
923 FreeXid(xid);
924 /* if we have gotten here we have written some data
925 and blocked, and the file has been freed on us while
926 we blocked so return what we managed to write */
927 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000928 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 /* we could deadlock if we called
931 filemap_fdatawait from here so tell
932 reopen_file not to flush data to server
933 now */
Jeff Layton15886172010-10-15 15:33:59 -0400934 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 if (rc != 0)
936 break;
937 }
938
939 rc = CIFSSMBWrite(xid, pTcon,
940 open_file->netfid,
941 min_t(const int, cifs_sb->wsize,
942 write_size - total_written),
943 *poffset, &bytes_written,
944 NULL, write_data + total_written, long_op);
945 }
946 if (rc || (bytes_written == 0)) {
947 if (total_written)
948 break;
949 else {
950 FreeXid(xid);
951 return rc;
952 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400953 } else {
954 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400956 }
Steve French133672e2007-11-13 22:41:37 +0000957 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 15 seconds is plenty */
959 }
960
Steve Frencha4544342005-08-24 13:59:35 -0700961 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000963/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100964 * inode->i_ctime = inode->i_mtime =
965 * current_fs_time(inode->i_sb);*/
966 if (total_written > 0) {
967 spin_lock(&inode->i_lock);
968 if (*poffset > inode->i_size)
969 i_size_write(inode, *poffset);
970 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100972 mark_inode_dirty_sync(inode);
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 FreeXid(xid);
975 return total_written;
976}
977
Jeff Layton7da4b492010-10-15 15:34:00 -0400978static ssize_t cifs_write(struct cifsFileInfo *open_file,
979 const char *write_data, size_t write_size,
980 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
982 int rc = 0;
983 unsigned int bytes_written = 0;
984 unsigned int total_written;
985 struct cifs_sb_info *cifs_sb;
986 struct cifsTconInfo *pTcon;
987 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -0400988 struct dentry *dentry = open_file->dentry;
989 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Jeff Layton7da4b492010-10-15 15:34:00 -0400991 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Joe Perchesb6b38f72010-04-21 03:50:45 +0000993 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -0400994 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Jeff Layton13cfb732010-09-29 19:51:11 -0400996 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001000 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 for (total_written = 0; write_size > total_written;
1002 total_written += bytes_written) {
1003 rc = -EAGAIN;
1004 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 /* we could deadlock if we called
1007 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001008 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001010 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (rc != 0)
1012 break;
1013 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001014 if (experimEnabled || (pTcon->ses->server &&
1015 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001016 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001017 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001018 struct kvec iov[2];
1019 unsigned int len;
1020
Steve French0ae0efa2005-10-10 10:57:19 -07001021 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001022 write_size - total_written);
1023 /* iov[0] is reserved for smb header */
1024 iov[1].iov_base = (char *)write_data +
1025 total_written;
1026 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001027 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001028 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001029 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001030 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001031 } else
Steve French60808232006-04-22 15:53:05 +00001032 rc = CIFSSMBWrite(xid, pTcon,
1033 open_file->netfid,
1034 min_t(const int, cifs_sb->wsize,
1035 write_size - total_written),
1036 *poffset, &bytes_written,
1037 write_data + total_written,
1038 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040 if (rc || (bytes_written == 0)) {
1041 if (total_written)
1042 break;
1043 else {
1044 FreeXid(xid);
1045 return rc;
1046 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001047 } else {
1048 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001050 }
Steve French133672e2007-11-13 22:41:37 +00001051 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 15 seconds is plenty */
1053 }
1054
Steve Frencha4544342005-08-24 13:59:35 -07001055 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Jeff Layton7da4b492010-10-15 15:34:00 -04001057 if (total_written > 0) {
1058 spin_lock(&dentry->d_inode->i_lock);
1059 if (*poffset > dentry->d_inode->i_size)
1060 i_size_write(dentry->d_inode, *poffset);
1061 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001063 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 FreeXid(xid);
1065 return total_written;
1066}
1067
Jeff Layton6508d902010-09-29 19:51:11 -04001068struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1069 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001070{
1071 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001072 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1073
1074 /* only filter by fsuid on multiuser mounts */
1075 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1076 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001077
Jeff Layton44772882010-10-15 15:34:03 -04001078 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001079 /* we could simply get the first_list_entry since write-only entries
1080 are always at the end of the list but since the first entry might
1081 have a close pending, we go through the whole list */
1082 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001083 if (fsuid_only && open_file->uid != current_fsuid())
1084 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001085 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001086 if (!open_file->invalidHandle) {
1087 /* found a good file */
1088 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001089 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001090 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001091 return open_file;
1092 } /* else might as well continue, and look for
1093 another, or simply have the caller reopen it
1094 again rather than trying to fix this handle */
1095 } else /* write only file */
1096 break; /* write only files are last so must be done */
1097 }
Jeff Layton44772882010-10-15 15:34:03 -04001098 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001099 return NULL;
1100}
Steve French630f3f0c2007-10-25 21:17:17 +00001101
Jeff Layton6508d902010-09-29 19:51:11 -04001102struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1103 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001104{
1105 struct cifsFileInfo *open_file;
Jeff Laytond3892292010-11-02 16:22:50 -04001106 struct cifs_sb_info *cifs_sb;
Jeff Layton2846d382008-09-22 21:33:33 -04001107 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001108 int rc;
Steve French6148a742005-10-05 12:23:19 -07001109
Steve French60808232006-04-22 15:53:05 +00001110 /* Having a null inode here (because mapping->host was set to zero by
1111 the VFS or MM) should not happen but we had reports of on oops (due to
1112 it being zero) during stress testcases so we need to check for it */
1113
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001114 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001115 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001116 dump_stack();
1117 return NULL;
1118 }
1119
Jeff Laytond3892292010-11-02 16:22:50 -04001120 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1121
Jeff Layton6508d902010-09-29 19:51:11 -04001122 /* only filter by fsuid on multiuser mounts */
1123 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1124 fsuid_only = false;
1125
Jeff Layton44772882010-10-15 15:34:03 -04001126 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001127refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001128 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001129 if (!any_available && open_file->pid != current->tgid)
1130 continue;
1131 if (fsuid_only && open_file->uid != current_fsuid())
1132 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001133 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001134 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001135
1136 if (!open_file->invalidHandle) {
1137 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001138 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001139 return open_file;
1140 }
Steve French8840dee2007-11-16 23:05:52 +00001141
Jeff Layton44772882010-10-15 15:34:03 -04001142 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001143
Steve French9b22b0b2007-10-02 01:11:08 +00001144 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001145 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001146 if (!rc)
1147 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001148
Steve Frenchcdff08e2010-10-21 22:46:14 +00001149 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001150 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001151 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001152
Steve Frenchcdff08e2010-10-21 22:46:14 +00001153 spin_lock(&cifs_file_list_lock);
1154
Steve French9b22b0b2007-10-02 01:11:08 +00001155 /* else we simply continue to the next entry. Thus
1156 we do not loop on reopen errors. If we
1157 can not reopen the file, for example if we
1158 reconnected to a server with another client
1159 racing to delete or lock the file we would not
1160 make progress if we restarted before the beginning
1161 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001162 }
1163 }
Jeff Layton2846d382008-09-22 21:33:33 -04001164 /* couldn't find useable FH with same pid, try any available */
1165 if (!any_available) {
1166 any_available = true;
1167 goto refind_writable;
1168 }
Jeff Layton44772882010-10-15 15:34:03 -04001169 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001170 return NULL;
1171}
1172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1174{
1175 struct address_space *mapping = page->mapping;
1176 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1177 char *write_data;
1178 int rc = -EFAULT;
1179 int bytes_written = 0;
1180 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001182 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 if (!mapping || !mapping->host)
1185 return -EFAULT;
1186
1187 inode = page->mapping->host;
1188 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 offset += (loff_t)from;
1191 write_data = kmap(page);
1192 write_data += from;
1193
1194 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1195 kunmap(page);
1196 return -EIO;
1197 }
1198
1199 /* racing with truncate? */
1200 if (offset > mapping->host->i_size) {
1201 kunmap(page);
1202 return 0; /* don't care */
1203 }
1204
1205 /* check to make sure that we are not extending the file */
1206 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001207 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Jeff Layton6508d902010-09-29 19:51:11 -04001209 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001210 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001211 bytes_written = cifs_write(open_file, write_data,
1212 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001213 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001215 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001216 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001217 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001218 else if (bytes_written < 0)
1219 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001220 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001221 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 rc = -EIO;
1223 }
1224
1225 kunmap(page);
1226 return rc;
1227}
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001230 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231{
Steve French37c0eb42005-10-05 14:50:29 -07001232 unsigned int bytes_to_write;
1233 unsigned int bytes_written;
1234 struct cifs_sb_info *cifs_sb;
1235 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001236 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001237 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001238 int range_whole = 0;
1239 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001240 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001241 int n_iov = 0;
1242 pgoff_t next;
1243 int nr_pages;
1244 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001245 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001246 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001247 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001248 struct page *page;
1249 struct pagevec pvec;
1250 int rc = 0;
1251 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001252 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Steve French37c0eb42005-10-05 14:50:29 -07001254 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001255
Steve French37c0eb42005-10-05 14:50:29 -07001256 /*
1257 * If wsize is smaller that the page cache size, default to writing
1258 * one page at a time via cifs_writepage
1259 */
1260 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1261 return generic_writepages(mapping, wbc);
1262
Steve French9a0c8232007-02-02 04:21:57 +00001263 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001264 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001265 return generic_writepages(mapping, wbc);
1266
Steve French37c0eb42005-10-05 14:50:29 -07001267 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001268 * if there's no open file, then this is likely to fail too,
1269 * but it'll at least handle the return. Maybe it should be
1270 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001271 */
Jeff Layton6508d902010-09-29 19:51:11 -04001272 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001273 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001274 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001275 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001276 }
1277
Jeff Layton13cfb732010-09-29 19:51:11 -04001278 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001279 if (!experimEnabled && tcon->ses->server->secMode &
1280 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1281 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001282 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001283 return generic_writepages(mapping, wbc);
1284 }
1285 cifsFileInfo_put(open_file);
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 xid = GetXid();
1288
Steve French37c0eb42005-10-05 14:50:29 -07001289 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001290 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001291 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001292 end = -1;
1293 } else {
1294 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1295 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1296 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1297 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001298 scanned = 1;
1299 }
1300retry:
1301 while (!done && (index <= end) &&
1302 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1303 PAGECACHE_TAG_DIRTY,
1304 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1305 int first;
1306 unsigned int i;
1307
Steve French37c0eb42005-10-05 14:50:29 -07001308 first = -1;
1309 next = 0;
1310 n_iov = 0;
1311 bytes_to_write = 0;
1312
1313 for (i = 0; i < nr_pages; i++) {
1314 page = pvec.pages[i];
1315 /*
1316 * At this point we hold neither mapping->tree_lock nor
1317 * lock on the page itself: the page may be truncated or
1318 * invalidated (changing page->mapping to NULL), or even
1319 * swizzled back from swapper_space to tmpfs file
1320 * mapping
1321 */
1322
1323 if (first < 0)
1324 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001325 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001326 break;
1327
1328 if (unlikely(page->mapping != mapping)) {
1329 unlock_page(page);
1330 break;
1331 }
1332
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001333 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001334 done = 1;
1335 unlock_page(page);
1336 break;
1337 }
1338
1339 if (next && (page->index != next)) {
1340 /* Not next consecutive page */
1341 unlock_page(page);
1342 break;
1343 }
1344
1345 if (wbc->sync_mode != WB_SYNC_NONE)
1346 wait_on_page_writeback(page);
1347
1348 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001349 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001350 unlock_page(page);
1351 break;
1352 }
Steve French84d2f072005-10-12 15:32:05 -07001353
Linus Torvaldscb876f42006-12-23 16:19:07 -08001354 /*
1355 * This actually clears the dirty bit in the radix tree.
1356 * See cifs_writepage() for more commentary.
1357 */
1358 set_page_writeback(page);
1359
Steve French84d2f072005-10-12 15:32:05 -07001360 if (page_offset(page) >= mapping->host->i_size) {
1361 done = 1;
1362 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001363 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001364 break;
1365 }
1366
Steve French37c0eb42005-10-05 14:50:29 -07001367 /*
1368 * BB can we get rid of this? pages are held by pvec
1369 */
1370 page_cache_get(page);
1371
Steve French84d2f072005-10-12 15:32:05 -07001372 len = min(mapping->host->i_size - page_offset(page),
1373 (loff_t)PAGE_CACHE_SIZE);
1374
Steve French37c0eb42005-10-05 14:50:29 -07001375 /* reserve iov[0] for the smb header */
1376 n_iov++;
1377 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001378 iov[n_iov].iov_len = len;
1379 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001380
1381 if (first < 0) {
1382 first = i;
1383 offset = page_offset(page);
1384 }
1385 next = page->index + 1;
1386 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1387 break;
1388 }
1389 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001390 open_file = find_writable_file(CIFS_I(mapping->host),
1391 false);
Steve French23e7dd72005-10-20 13:44:56 -07001392 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001393 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001394 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001395 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001396 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001397 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001398 bytes_to_write, offset,
1399 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001400 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001401 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001402 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001403 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001404
1405 if (rc || bytes_written < bytes_to_write) {
1406 cERROR(1, "Write2 ret %d, wrote %d",
1407 rc, bytes_written);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001408 mapping_set_error(mapping, rc);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001409 } else {
1410 cifs_stats_bytes_written(tcon, bytes_written);
1411 }
1412
Steve French37c0eb42005-10-05 14:50:29 -07001413 for (i = 0; i < n_iov; i++) {
1414 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001415 /* Should we also set page error on
1416 success rc but too little data written? */
1417 /* BB investigate retry logic on temporary
1418 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001419 when page marked as error */
1420 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001421 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001422 kunmap(page);
1423 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001424 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001425 page_cache_release(page);
1426 }
1427 if ((wbc->nr_to_write -= n_iov) <= 0)
1428 done = 1;
1429 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001430 } else
1431 /* Need to re-find the pages we skipped */
1432 index = pvec.pages[0]->index + 1;
1433
Steve French37c0eb42005-10-05 14:50:29 -07001434 pagevec_release(&pvec);
1435 }
1436 if (!scanned && !done) {
1437 /*
1438 * We hit the last page and there is more work to be done: wrap
1439 * back to the start of the file
1440 */
1441 scanned = 1;
1442 index = 0;
1443 goto retry;
1444 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001445 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001446 mapping->writeback_index = index;
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001449 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 return rc;
1451}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001453static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
1455 int rc = -EFAULT;
1456 int xid;
1457
1458 xid = GetXid();
1459/* BB add check for wbc flags */
1460 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001461 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001462 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001463
1464 /*
1465 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1466 *
1467 * A writepage() implementation always needs to do either this,
1468 * or re-dirty the page with "redirty_page_for_writepage()" in
1469 * the case of a failure.
1470 *
1471 * Just unlocking the page will cause the radix tree tag-bits
1472 * to fail to update with the state of the page correctly.
1473 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001474 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1476 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1477 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001478 end_page_writeback(page);
1479 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 FreeXid(xid);
1481 return rc;
1482}
1483
Nick Piggind9414772008-09-24 11:32:59 -04001484static int cifs_write_end(struct file *file, struct address_space *mapping,
1485 loff_t pos, unsigned len, unsigned copied,
1486 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
Nick Piggind9414772008-09-24 11:32:59 -04001488 int rc;
1489 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
Joe Perchesb6b38f72010-04-21 03:50:45 +00001491 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1492 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001493
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001494 if (PageChecked(page)) {
1495 if (copied == len)
1496 SetPageUptodate(page);
1497 ClearPageChecked(page);
1498 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001499 SetPageUptodate(page);
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001502 char *page_data;
1503 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1504 int xid;
1505
1506 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 /* this is probably better than directly calling
1508 partialpage_write since in this function the file handle is
1509 known which we might as well leverage */
1510 /* BB check if anything else missing out of ppw
1511 such as updating last write time */
1512 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001513 rc = cifs_write(file->private_data, page_data + offset,
1514 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001515 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001517
1518 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001519 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001520 rc = copied;
1521 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 set_page_dirty(page);
1523 }
1524
Nick Piggind9414772008-09-24 11:32:59 -04001525 if (rc > 0) {
1526 spin_lock(&inode->i_lock);
1527 if (pos > inode->i_size)
1528 i_size_write(inode, pos);
1529 spin_unlock(&inode->i_lock);
1530 }
1531
1532 unlock_page(page);
1533 page_cache_release(page);
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 return rc;
1536}
1537
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001538int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539{
1540 int xid;
1541 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001542 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001543 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001544 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546 xid = GetXid();
1547
Joe Perchesb6b38f72010-04-21 03:50:45 +00001548 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001549 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001550
Jeff Laytoncea21802007-11-20 23:19:03 +00001551 rc = filemap_write_and_wait(inode->i_mapping);
1552 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001553 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1554
Jeff Layton13cfb732010-09-29 19:51:11 -04001555 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001556 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001557 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001558 }
Steve Frenchb298f222009-02-21 21:17:43 +00001559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 FreeXid(xid);
1561 return rc;
1562}
1563
NeilBrown3978d7172006-03-26 01:37:17 -08001564/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
1566 struct address_space *mapping;
1567 struct inode *inode;
1568 unsigned long index = page->index;
1569 unsigned int rpages = 0;
1570 int rc = 0;
1571
Steve Frenchf19159d2010-04-21 04:12:10 +00001572 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 mapping = page->mapping;
1574 if (!mapping)
1575 return 0;
1576 inode = mapping->host;
1577 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001578 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001580/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1582
Joe Perchesb6b38f72010-04-21 03:50:45 +00001583/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
NeilBrown3978d7172006-03-26 01:37:17 -08001585#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 if (rc < 0)
1587 return rc;
1588 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001589#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590} */
1591
1592/*
1593 * As file closes, flush all cached write data for this inode checking
1594 * for write behind errors.
1595 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001596int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001598 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 int rc = 0;
1600
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001601 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001602 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001603
Joe Perchesb6b38f72010-04-21 03:50:45 +00001604 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606 return rc;
1607}
1608
1609ssize_t cifs_user_read(struct file *file, char __user *read_data,
1610 size_t read_size, loff_t *poffset)
1611{
1612 int rc = -EACCES;
1613 unsigned int bytes_read = 0;
1614 unsigned int total_read = 0;
1615 unsigned int current_read_size;
1616 struct cifs_sb_info *cifs_sb;
1617 struct cifsTconInfo *pTcon;
1618 int xid;
1619 struct cifsFileInfo *open_file;
1620 char *smb_read_data;
1621 char __user *current_offset;
1622 struct smb_com_read_rsp *pSMBr;
1623
1624 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001625 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301628 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301630 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001632 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001633 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Steve Frenchad7a2922008-02-07 23:25:02 +00001635 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001636 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 for (total_read = 0, current_offset = read_data;
1639 read_size > total_read;
1640 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001641 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 cifs_sb->rsize);
1643 rc = -EAGAIN;
1644 smb_read_data = NULL;
1645 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001646 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001647 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001648 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 if (rc != 0)
1650 break;
1651 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001652 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001653 open_file->netfid,
1654 current_read_size, *poffset,
1655 &bytes_read, &smb_read_data,
1656 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001659 if (copy_to_user(current_offset,
1660 smb_read_data +
1661 4 /* RFC1001 length field */ +
1662 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001663 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001664 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001665
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001666 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001667 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001668 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001669 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 smb_read_data = NULL;
1671 }
1672 }
1673 if (rc || (bytes_read == 0)) {
1674 if (total_read) {
1675 break;
1676 } else {
1677 FreeXid(xid);
1678 return rc;
1679 }
1680 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001681 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 *poffset += bytes_read;
1683 }
1684 }
1685 FreeXid(xid);
1686 return total_read;
1687}
1688
1689
1690static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1691 loff_t *poffset)
1692{
1693 int rc = -EACCES;
1694 unsigned int bytes_read = 0;
1695 unsigned int total_read;
1696 unsigned int current_read_size;
1697 struct cifs_sb_info *cifs_sb;
1698 struct cifsTconInfo *pTcon;
1699 int xid;
1700 char *current_offset;
1701 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001702 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001705 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
1707 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301708 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301710 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001712 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001713 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001716 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001718 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 read_size > total_read;
1720 total_read += bytes_read, current_offset += bytes_read) {
1721 current_read_size = min_t(const int, read_size - total_read,
1722 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001723 /* For windows me and 9x we do not want to request more
1724 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001725 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001726 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1727 current_read_size = min_t(const int, current_read_size,
1728 pTcon->ses->server->maxBuf - 128);
1729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 rc = -EAGAIN;
1731 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001732 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001733 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (rc != 0)
1735 break;
1736 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001737 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001738 open_file->netfid,
1739 current_read_size, *poffset,
1740 &bytes_read, &current_offset,
1741 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743 if (rc || (bytes_read == 0)) {
1744 if (total_read) {
1745 break;
1746 } else {
1747 FreeXid(xid);
1748 return rc;
1749 }
1750 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001751 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 *poffset += bytes_read;
1753 }
1754 }
1755 FreeXid(xid);
1756 return total_read;
1757}
1758
1759int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1760{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 int rc, xid;
1762
1763 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001764 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001766 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 FreeXid(xid);
1768 return rc;
1769 }
1770 rc = generic_file_mmap(file, vma);
1771 FreeXid(xid);
1772 return rc;
1773}
1774
1775
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001776static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001777 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778{
1779 struct page *page;
1780 char *target;
1781
1782 while (bytes_read > 0) {
1783 if (list_empty(pages))
1784 break;
1785
1786 page = list_entry(pages->prev, struct page, lru);
1787 list_del(&page->lru);
1788
Nick Piggin315e9952010-04-21 03:18:28 +00001789 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 GFP_KERNEL)) {
1791 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001792 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001793 data += PAGE_CACHE_SIZE;
1794 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 continue;
1796 }
Jeff Layton06b43672010-06-01 10:54:45 -04001797 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001799 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 if (PAGE_CACHE_SIZE > bytes_read) {
1802 memcpy(target, data, bytes_read);
1803 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 PAGE_CACHE_SIZE - bytes_read);
1806 bytes_read = 0;
1807 } else {
1808 memcpy(target, data, PAGE_CACHE_SIZE);
1809 bytes_read -= PAGE_CACHE_SIZE;
1810 }
1811 kunmap_atomic(target, KM_USER0);
1812
1813 flush_dcache_page(page);
1814 SetPageUptodate(page);
1815 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301817
1818 /* add page to FS-Cache */
1819 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
1821 return;
1822}
1823
1824static int cifs_readpages(struct file *file, struct address_space *mapping,
1825 struct list_head *page_list, unsigned num_pages)
1826{
1827 int rc = -EACCES;
1828 int xid;
1829 loff_t offset;
1830 struct page *page;
1831 struct cifs_sb_info *cifs_sb;
1832 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001833 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001834 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 char *smb_read_data = NULL;
1836 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001838 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 xid = GetXid();
1841 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301842 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301844 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001846 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001847 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001848 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001849
Suresh Jayaraman56698232010-07-05 18:13:25 +05301850 /*
1851 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1852 * immediately if the cookie is negative
1853 */
1854 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1855 &num_pages);
1856 if (rc == 0)
1857 goto read_complete;
1858
Steve Frenchf19159d2010-04-21 04:12:10 +00001859 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 for (i = 0; i < num_pages; ) {
1861 unsigned contig_pages;
1862 struct page *tmp_page;
1863 unsigned long expected_index;
1864
1865 if (list_empty(page_list))
1866 break;
1867
1868 page = list_entry(page_list->prev, struct page, lru);
1869 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1870
1871 /* count adjacent pages that we will read into */
1872 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001873 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001875 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (tmp_page->index == expected_index) {
1877 contig_pages++;
1878 expected_index++;
1879 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001880 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
1882 if (contig_pages + i > num_pages)
1883 contig_pages = num_pages - i;
1884
1885 /* for reads over a certain size could initiate async
1886 read ahead */
1887
1888 read_size = contig_pages * PAGE_CACHE_SIZE;
1889 /* Read size needs to be in multiples of one page */
1890 read_size = min_t(const unsigned int, read_size,
1891 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001892 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1893 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 rc = -EAGAIN;
1895 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001896 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001897 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (rc != 0)
1899 break;
1900 }
1901
Steve Frenchbfa0d752005-08-31 21:50:37 -07001902 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001903 open_file->netfid,
1904 read_size, offset,
1905 &bytes_read, &smb_read_data,
1906 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001907 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001908 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001910 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001911 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001912 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001913 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 smb_read_data = NULL;
1915 }
1916 }
1917 }
1918 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001919 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 break;
1921 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001922 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1924 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1925 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001926 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001929 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001930 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 i++; /* account for partial page */
1932
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001933 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001935 /* BB do we need to verify this common case ?
1936 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 we will hit it on next read */
1938
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001939 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001942 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001943 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001944 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001945 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 break;
1948 }
1949 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001950 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001951 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001952 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001953 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 smb_read_data = NULL;
1955 }
1956 bytes_read = 0;
1957 }
1958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959/* need to free smb_read_data buf before exit */
1960 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001961 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001962 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001963 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001964 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Suresh Jayaraman56698232010-07-05 18:13:25 +05301968read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 FreeXid(xid);
1970 return rc;
1971}
1972
1973static int cifs_readpage_worker(struct file *file, struct page *page,
1974 loff_t *poffset)
1975{
1976 char *read_data;
1977 int rc;
1978
Suresh Jayaraman56698232010-07-05 18:13:25 +05301979 /* Is the page cached? */
1980 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
1981 if (rc == 0)
1982 goto read_complete;
1983
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 page_cache_get(page);
1985 read_data = kmap(page);
1986 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 if (rc < 0)
1991 goto io_error;
1992 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001993 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001994
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001995 file->f_path.dentry->d_inode->i_atime =
1996 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001997
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 if (PAGE_CACHE_SIZE > rc)
1999 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2000
2001 flush_dcache_page(page);
2002 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302003
2004 /* send this page to the cache */
2005 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002010 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302012
2013read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 return rc;
2015}
2016
2017static int cifs_readpage(struct file *file, struct page *page)
2018{
2019 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2020 int rc = -EACCES;
2021 int xid;
2022
2023 xid = GetXid();
2024
2025 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302026 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302028 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030
Joe Perchesb6b38f72010-04-21 03:50:45 +00002031 cFYI(1, "readpage %p at offset %d 0x%x\n",
2032 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033
2034 rc = cifs_readpage_worker(file, page, &offset);
2035
2036 unlock_page(page);
2037
2038 FreeXid(xid);
2039 return rc;
2040}
2041
Steve Frencha403a0a2007-07-26 15:54:16 +00002042static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2043{
2044 struct cifsFileInfo *open_file;
2045
Jeff Layton44772882010-10-15 15:34:03 -04002046 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002047 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002048 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002049 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002050 return 1;
2051 }
2052 }
Jeff Layton44772882010-10-15 15:34:03 -04002053 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002054 return 0;
2055}
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057/* We do not want to update the file size from server for inodes
2058 open for write - to avoid races with writepage extending
2059 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002060 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 but this is tricky to do without racing with writebehind
2062 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002063bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
Steve Frencha403a0a2007-07-26 15:54:16 +00002065 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002066 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002067
Steve Frencha403a0a2007-07-26 15:54:16 +00002068 if (is_inode_writable(cifsInode)) {
2069 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002070 struct cifs_sb_info *cifs_sb;
2071
Steve Frenchc32a0b62006-01-12 14:41:28 -08002072 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002073 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002074 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002075 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002076 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002077 }
2078
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002079 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002080 return true;
Steve French7ba52632007-02-08 18:14:13 +00002081
Steve French4b18f2a2008-04-29 00:06:05 +00002082 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002083 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002084 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085}
2086
Nick Piggind9414772008-09-24 11:32:59 -04002087static int cifs_write_begin(struct file *file, struct address_space *mapping,
2088 loff_t pos, unsigned len, unsigned flags,
2089 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090{
Nick Piggind9414772008-09-24 11:32:59 -04002091 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2092 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002093 loff_t page_start = pos & PAGE_MASK;
2094 loff_t i_size;
2095 struct page *page;
2096 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Joe Perchesb6b38f72010-04-21 03:50:45 +00002098 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002099
Nick Piggin54566b22009-01-04 12:00:53 -08002100 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002101 if (!page) {
2102 rc = -ENOMEM;
2103 goto out;
2104 }
Nick Piggind9414772008-09-24 11:32:59 -04002105
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002106 if (PageUptodate(page))
2107 goto out;
Steve French8a236262007-03-06 00:31:00 +00002108
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002109 /*
2110 * If we write a full page it will be up to date, no need to read from
2111 * the server. If the write is short, we'll end up doing a sync write
2112 * instead.
2113 */
2114 if (len == PAGE_CACHE_SIZE)
2115 goto out;
2116
2117 /*
2118 * optimize away the read when we have an oplock, and we're not
2119 * expecting to use any of the data we'd be reading in. That
2120 * is, when the page lies beyond the EOF, or straddles the EOF
2121 * and the write will cover all of the existing data.
2122 */
2123 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2124 i_size = i_size_read(mapping->host);
2125 if (page_start >= i_size ||
2126 (offset == 0 && (pos + len) >= i_size)) {
2127 zero_user_segments(page, 0, offset,
2128 offset + len,
2129 PAGE_CACHE_SIZE);
2130 /*
2131 * PageChecked means that the parts of the page
2132 * to which we're not writing are considered up
2133 * to date. Once the data is copied to the
2134 * page, it can be set uptodate.
2135 */
2136 SetPageChecked(page);
2137 goto out;
2138 }
2139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Nick Piggind9414772008-09-24 11:32:59 -04002141 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002142 /*
2143 * might as well read a page, it is fast enough. If we get
2144 * an error, we don't need to return it. cifs_write_end will
2145 * do a sync write instead since PG_uptodate isn't set.
2146 */
2147 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002148 } else {
2149 /* we could try using another file handle if there is one -
2150 but how would we lock it to prevent close of that handle
2151 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002152 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002153 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002154out:
2155 *pagep = page;
2156 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157}
2158
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302159static int cifs_release_page(struct page *page, gfp_t gfp)
2160{
2161 if (PagePrivate(page))
2162 return 0;
2163
2164 return cifs_fscache_release_page(page, gfp);
2165}
2166
2167static void cifs_invalidate_page(struct page *page, unsigned long offset)
2168{
2169 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2170
2171 if (offset == 0)
2172 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2173}
2174
Tejun Heo9b646972010-07-20 22:09:02 +02002175void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002176{
2177 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2178 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002179 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002180 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002181 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002182
2183 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002184 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002185 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002186 else
Al Viro8737c932009-12-24 06:47:55 -05002187 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002188 rc = filemap_fdatawrite(inode->i_mapping);
2189 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002190 rc = filemap_fdatawait(inode->i_mapping);
2191 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002192 invalidate_remote_inode(inode);
2193 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002195 }
2196
2197 /*
2198 * releasing stale oplock after recent reconnect of smb session using
2199 * a now incorrect file handle is not a data integrity issue but do
2200 * not bother sending an oplock release if session to server still is
2201 * disconnected since oplock already released by the server
2202 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002203 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002204 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2205 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002206 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002207 }
Tejun Heo9b646972010-07-20 22:09:02 +02002208
2209 /*
2210 * We might have kicked in before is_valid_oplock_break()
2211 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302212 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002213 */
Jeff Layton44772882010-10-15 15:34:03 -04002214 spin_lock(&cifs_file_list_lock);
2215 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002216
2217 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002218}
2219
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002220/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002221void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002222{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002223 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002224 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002225}
2226
Tejun Heo9b646972010-07-20 22:09:02 +02002227void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002228{
Jeff Laytonebe2e912010-11-10 10:19:10 -05002229 struct super_block *sb = cfile->dentry->d_sb;
2230
Jeff Layton3bc303c2009-09-21 06:47:50 -04002231 cifsFileInfo_put(cfile);
Jeff Laytonebe2e912010-11-10 10:19:10 -05002232 cifs_sb_deactive(sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002233}
2234
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002235const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 .readpage = cifs_readpage,
2237 .readpages = cifs_readpages,
2238 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002239 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002240 .write_begin = cifs_write_begin,
2241 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302243 .releasepage = cifs_release_page,
2244 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 /* .sync_page = cifs_sync_page, */
2246 /* .direct_IO = */
2247};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002248
2249/*
2250 * cifs_readpages requires the server to support a buffer large enough to
2251 * contain the header plus one complete page of data. Otherwise, we need
2252 * to leave cifs_readpages out of the address space operations.
2253 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002254const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002255 .readpage = cifs_readpage,
2256 .writepage = cifs_writepage,
2257 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002258 .write_begin = cifs_write_begin,
2259 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002260 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302261 .releasepage = cifs_release_page,
2262 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002263 /* .sync_page = cifs_sync_page, */
2264 /* .direct_IO = */
2265};