blob: 1b26c2717599a0c386847fdaa826ef7c98bf9472 [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);
Pavel Shilovsky4f8ba8a2010-11-21 22:36:12 +0300290 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000291 struct cifsLockInfo *li, *tmp;
292
293 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400294 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000295 spin_unlock(&cifs_file_list_lock);
296 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400297 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000298
299 /* remove it from the lists */
300 list_del(&cifs_file->flist);
301 list_del(&cifs_file->tlist);
302
303 if (list_empty(&cifsi->openFileList)) {
304 cFYI(1, "closing last open instance for inode %p",
305 cifs_file->dentry->d_inode);
Pavel Shilovsky4f8ba8a2010-11-21 22:36:12 +0300306
307 /* in strict cache mode we need invalidate mapping on the last
308 close because it may cause a error when we open this file
309 again and get at least level II oplock */
310 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
311 CIFS_I(inode)->invalid_mapping = true;
312
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300313 cifs_set_oplock_level(cifsi, 0);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000314 }
315 spin_unlock(&cifs_file_list_lock);
316
317 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
318 int xid, rc;
319
320 xid = GetXid();
321 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
322 FreeXid(xid);
323 }
324
325 /* Delete any outstanding lock records. We'll lose them when the file
326 * is closed anyway.
327 */
328 mutex_lock(&cifs_file->lock_mutex);
329 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
330 list_del(&li->llist);
331 kfree(li);
332 }
333 mutex_unlock(&cifs_file->lock_mutex);
334
335 cifs_put_tlink(cifs_file->tlink);
336 dput(cifs_file->dentry);
337 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400338}
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340int cifs_open(struct inode *inode, struct file *file)
341{
342 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400343 int xid;
344 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000346 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400347 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400348 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 char *full_path = NULL;
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300351 bool posix_open_ok = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 __u16 netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 xid = GetXid();
355
356 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400357 tlink = cifs_sb_tlink(cifs_sb);
358 if (IS_ERR(tlink)) {
359 FreeXid(xid);
360 return PTR_ERR(tlink);
361 }
362 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Steve Frencha6ce4932009-04-09 01:14:32 +0000364 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800366 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530368 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400369 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
371
Joe Perchesb6b38f72010-04-21 03:50:45 +0000372 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
373 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000374
375 if (oplockEnabled)
376 oplock = REQ_OPLOCK;
377 else
378 oplock = 0;
379
Steve French64cc2c62009-03-04 19:54:08 +0000380 if (!tcon->broken_posix_open && tcon->unix_ext &&
381 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000382 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
383 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000384 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400385 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000386 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400387 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000388 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000389 cFYI(1, "posix open succeeded");
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300390 posix_open_ok = true;
Steve French64cc2c62009-03-04 19:54:08 +0000391 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
392 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000393 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000394 " unexpected error on SMB posix open"
395 ", disabling posix open support."
396 " Check if server update available.",
397 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000399 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000400 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
401 (rc != -EOPNOTSUPP)) /* path not found or net err */
402 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000403 /* else fallthrough to retry open the old way on network i/o
404 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000405 }
406
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300407 if (!posix_open_ok) {
408 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
409 file->f_flags, &oplock, &netfid, xid);
410 if (rc)
411 goto out;
412 }
Jeff Layton47c78b72010-06-16 13:40:17 -0400413
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400414 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400415 if (pCifsFile == NULL) {
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300416 CIFSSMBClose(xid, tcon, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 rc = -ENOMEM;
418 goto out;
419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530421 cifs_fscache_set_inode_cookie(inode, file);
422
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300423 if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 /* time to set mode which we can not set earlier due to
425 problems creating new read-only files */
Pavel Shilovsky7e12edd2010-11-25 17:20:20 +0300426 struct cifs_unix_set_info_args args = {
427 .mode = inode->i_mode,
428 .uid = NO_CHANGE_64,
429 .gid = NO_CHANGE_64,
430 .ctime = NO_CHANGE_64,
431 .atime = NO_CHANGE_64,
432 .mtime = NO_CHANGE_64,
433 .device = 0,
434 };
Jeff Laytond44a9fe2011-01-07 11:30:29 -0500435 CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
436 pCifsFile->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438
439out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 kfree(full_path);
441 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400442 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return rc;
444}
445
Adrian Bunk04187262006-06-30 18:23:04 +0200446/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447/* to server was lost */
448static int cifs_relock_file(struct cifsFileInfo *cifsFile)
449{
450 int rc = 0;
451
452/* BB list all locks open on this file and relock */
453
454 return rc;
455}
456
Jeff Layton15886172010-10-15 15:33:59 -0400457static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400460 int xid;
461 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000463 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000465 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 char *full_path = NULL;
467 int desiredAccess;
468 int disposition = FILE_OPEN;
469 __u16 netfid;
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400472 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000473 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400474 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530475 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530477 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479
Jeff Layton15886172010-10-15 15:33:59 -0400480 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400482 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484/* can not grab rename sem here because various ops, including
485 those that already have the rename sem can end up causing writepage
486 to get called and if the server was down that means we end up here,
487 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400488 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000490 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400491 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000493 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 }
495
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400497 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (oplockEnabled)
500 oplock = REQ_OPLOCK;
501 else
Steve French4b18f2a2008-04-29 00:06:05 +0000502 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Steve French7fc8f4e2009-02-23 20:43:11 +0000504 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
505 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
506 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400507
508 /*
509 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
510 * original open. Must mask them off for a reopen.
511 */
Jeff Layton15886172010-10-15 15:33:59 -0400512 unsigned int oflags = pCifsFile->f_flags &
513 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400514
Jeff Layton2422f672010-06-16 13:40:16 -0400515 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000516 cifs_sb->mnt_file_mode /* ignored */,
517 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000518 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000519 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000520 goto reopen_success;
521 }
522 /* fallthrough to retry open the old way on errors, especially
523 in the reconnect path it is important to retry hard */
524 }
525
Jeff Layton15886172010-10-15 15:33:59 -0400526 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000529 by SMBOpen and then calling get_inode_info with returned buf
530 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 and server version of file size can be stale. If we knew for sure
532 that inode was not dirty locally we could do this */
533
Steve French7fc8f4e2009-02-23 20:43:11 +0000534 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700537 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400539 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000540 cFYI(1, "cifs_open returned 0x%x", rc);
541 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400542 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 }
Jeff Layton15886172010-10-15 15:33:59 -0400544
545reopen_success:
546 pCifsFile->netfid = netfid;
547 pCifsFile->invalidHandle = false;
548 mutex_unlock(&pCifsFile->fh_mutex);
549 pCifsInode = CIFS_I(inode);
550
551 if (can_flush) {
552 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400553 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400554
Jeff Layton15886172010-10-15 15:33:59 -0400555 if (tcon->unix_ext)
556 rc = cifs_get_inode_info_unix(&inode,
557 full_path, inode->i_sb, xid);
558 else
559 rc = cifs_get_inode_info(&inode,
560 full_path, NULL, inode->i_sb,
561 xid, NULL);
562 } /* else we are writing out data to server already
563 and could deadlock if we tried to flush data, and
564 since we do not know if we have data that would
565 invalidate the current end of file on the server
566 we can not go to the server to get the new inod
567 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300568
Pavel Shilovskyc6723622010-11-03 10:58:57 +0300569 cifs_set_oplock_level(pCifsInode, oplock);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300570
Jeff Layton15886172010-10-15 15:33:59 -0400571 cifs_relock_file(pCifsFile);
572
573reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 kfree(full_path);
575 FreeXid(xid);
576 return rc;
577}
578
579int cifs_close(struct inode *inode, struct file *file)
580{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000581 cifsFileInfo_put(file->private_data);
582 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Steve Frenchcdff08e2010-10-21 22:46:14 +0000584 /* return code from the ->release op is always ignored */
585 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588int cifs_closedir(struct inode *inode, struct file *file)
589{
590 int rc = 0;
591 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700592 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 char *ptmp;
594
Joe Perchesb6b38f72010-04-21 03:50:45 +0000595 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 xid = GetXid();
598
599 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400600 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Joe Perchesb6b38f72010-04-21 03:50:45 +0000602 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400603 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000604 if (!pCFileStruct->srch_inf.endOfSearch &&
605 !pCFileStruct->invalidHandle) {
606 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400607 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000609 cFYI(1, "Closing uncompleted readdir with rc %d",
610 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 /* not much we can do if it fails anyway, ignore rc */
612 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000613 } else
Jeff Layton44772882010-10-15 15:34:03 -0400614 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
616 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000617 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000619 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000620 cifs_small_buf_release(ptmp);
621 else
622 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400624 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 kfree(file->private_data);
626 file->private_data = NULL;
627 }
628 /* BB can we lock the filestruct while this is going on? */
629 FreeXid(xid);
630 return rc;
631}
632
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000633static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
634 __u64 offset, __u8 lockType)
635{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000636 struct cifsLockInfo *li =
637 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000638 if (li == NULL)
639 return -ENOMEM;
640 li->offset = offset;
641 li->length = len;
642 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000643 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000644 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000645 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000646 return 0;
647}
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
650{
651 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 __u32 numLock = 0;
653 __u32 numUnlock = 0;
654 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000655 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000657 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000658 __u16 netfid;
659 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000660 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 length = 1 + pfLock->fl_end - pfLock->fl_start;
663 rc = -EACCES;
664 xid = GetXid();
665
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000668 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000669 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000672 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000677 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 }
679 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000680 cFYI(1, "Process suspended by mandatory locking - "
681 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000683 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000684 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000686 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000689 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 numLock = 1;
691 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000694 /* Check if unlock includes more than
695 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 lockType |= LOCKING_ANDX_SHARED_LOCK;
699 numLock = 1;
700 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 numLock = 1;
703 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000704 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 lockType |= LOCKING_ANDX_SHARED_LOCK;
706 numLock = 1;
707 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000708 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800710 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400711 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Steve French08547b02006-02-28 22:39:25 +0000712 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Steve French13a6e422008-12-02 17:24:33 +0000714 if ((tcon->ses->capabilities & CAP_UNIX) &&
715 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000716 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000717 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000718 /* BB add code here to normalize offset and length to
719 account for negative length which we can not accept over the
720 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000722 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000723 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000724 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000725 posix_lock_type = CIFS_RDLCK;
726 else
727 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000728 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000729 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000730 posix_lock_type, wait_flag);
731 FreeXid(xid);
732 return rc;
733 }
734
735 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000736 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300737 0, 1, lockType, 0 /* wait flag */, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000739 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 pfLock->fl_start, 1 /* numUnlock */ ,
741 0 /* numLock */ , lockType,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300742 0 /* wait flag */, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 pfLock->fl_type = F_UNLCK;
744 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000745 cERROR(1, "Error unlocking previously locked "
746 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 rc = 0;
748
749 } else {
750 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400751 rc = 0;
752
753 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
754 pfLock->fl_type = F_WRLCK;
755 } else {
756 rc = CIFSSMBLock(xid, tcon, netfid, length,
757 pfLock->fl_start, 0, 1,
758 lockType | LOCKING_ANDX_SHARED_LOCK,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300759 0 /* wait flag */, 0);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400760 if (rc == 0) {
761 rc = CIFSSMBLock(xid, tcon, netfid,
762 length, pfLock->fl_start, 1, 0,
763 lockType |
764 LOCKING_ANDX_SHARED_LOCK,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300765 0 /* wait flag */, 0);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400766 pfLock->fl_type = F_RDLCK;
767 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000768 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400769 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000770 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400771 rc = 0;
772 } else {
773 pfLock->fl_type = F_WRLCK;
774 rc = 0;
775 }
776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
778
779 FreeXid(xid);
780 return rc;
781 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000782
783 if (!numLock && !numUnlock) {
784 /* if no lock or unlock then nothing
785 to do since we do not know what it is */
786 FreeXid(xid);
787 return -EOPNOTSUPP;
788 }
789
790 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000791 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000792 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000793 posix_lock_type = CIFS_RDLCK;
794 else
795 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000796
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000797 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000798 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799
Steve French13a6e422008-12-02 17:24:33 +0000800 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000801 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000802 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000803 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700804 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000805
806 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000807 rc = CIFSSMBLock(xid, tcon, netfid, length,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300808 pfLock->fl_start, 0, numLock, lockType,
809 wait_flag, 0);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000810
811 if (rc == 0) {
812 /* For Windows locks we must store them. */
813 rc = store_file_lock(fid, length,
814 pfLock->fl_start, lockType);
815 }
816 } else if (numUnlock) {
817 /* For each stored lock that this unlock overlaps
818 completely, unlock it. */
819 int stored_rc = 0;
820 struct cifsLockInfo *li, *tmp;
821
Steve French6b70c952006-09-21 07:35:29 +0000822 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000823 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000824 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
825 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000826 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000827 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000828 stored_rc = CIFSSMBLock(xid, tcon,
Pavel Shilovsky12fed002011-01-17 20:15:44 +0300829 netfid, li->length,
830 li->offset, 1, 0,
831 li->type, false, 0);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000832 if (stored_rc)
833 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000834 else {
835 list_del(&li->llist);
836 kfree(li);
837 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000838 }
839 }
Roland Dreier796e5662007-05-03 04:33:45 +0000840 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000841 }
842 }
843
Steve Frenchd634cc12005-08-26 14:42:59 -0500844 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 posix_lock_file_wait(file, pfLock);
846 FreeXid(xid);
847 return rc;
848}
849
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400850/* update the file size (if needed) after a write */
851static void
852cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
853 unsigned int bytes_written)
854{
855 loff_t end_of_write = offset + bytes_written;
856
857 if (end_of_write > cifsi->server_eof)
858 cifsi->server_eof = end_of_write;
859}
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861ssize_t cifs_user_write(struct file *file, const char __user *write_data,
862 size_t write_size, loff_t *poffset)
863{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100864 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 int rc = 0;
866 unsigned int bytes_written = 0;
867 unsigned int total_written;
868 struct cifs_sb_info *cifs_sb;
869 struct cifsTconInfo *pTcon;
Jeff Layton77499812011-01-11 07:24:23 -0500870 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100872 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800874 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Joe Perchesb6b38f72010-04-21 03:50:45 +0000876 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
877 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 if (file->private_data == NULL)
880 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700881
Joe Perchesc21dfb62010-07-12 13:50:14 -0700882 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400883 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000884
Jeff Layton838726c2008-08-28 07:54:59 -0400885 rc = generic_write_checks(file, poffset, &write_size, 0);
886 if (rc)
887 return rc;
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 for (total_written = 0; write_size > total_written;
892 total_written += bytes_written) {
893 rc = -EAGAIN;
894 while (rc == -EAGAIN) {
895 if (file->private_data == NULL) {
896 /* file has been closed on us */
897 FreeXid(xid);
898 /* if we have gotten here we have written some data
899 and blocked, and the file has been freed on us while
900 we blocked so return what we managed to write */
901 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 /* we could deadlock if we called
905 filemap_fdatawait from here so tell
906 reopen_file not to flush data to server
907 now */
Jeff Layton15886172010-10-15 15:33:59 -0400908 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (rc != 0)
910 break;
911 }
912
913 rc = CIFSSMBWrite(xid, pTcon,
914 open_file->netfid,
915 min_t(const int, cifs_sb->wsize,
916 write_size - total_written),
917 *poffset, &bytes_written,
Jeff Layton77499812011-01-11 07:24:23 -0500918 NULL, write_data + total_written, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 }
920 if (rc || (bytes_written == 0)) {
921 if (total_written)
922 break;
923 else {
924 FreeXid(xid);
925 return rc;
926 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400927 } else {
928 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
932
Steve Frencha4544342005-08-24 13:59:35 -0700933 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000935/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100936 * inode->i_ctime = inode->i_mtime =
937 * current_fs_time(inode->i_sb);*/
938 if (total_written > 0) {
939 spin_lock(&inode->i_lock);
940 if (*poffset > inode->i_size)
941 i_size_write(inode, *poffset);
942 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100944 mark_inode_dirty_sync(inode);
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 FreeXid(xid);
947 return total_written;
948}
949
Jeff Layton7da4b492010-10-15 15:34:00 -0400950static ssize_t cifs_write(struct cifsFileInfo *open_file,
951 const char *write_data, size_t write_size,
952 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 int rc = 0;
955 unsigned int bytes_written = 0;
956 unsigned int total_written;
957 struct cifs_sb_info *cifs_sb;
958 struct cifsTconInfo *pTcon;
Jeff Layton77499812011-01-11 07:24:23 -0500959 int xid;
Jeff Layton7da4b492010-10-15 15:34:00 -0400960 struct dentry *dentry = open_file->dentry;
961 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Jeff Layton7da4b492010-10-15 15:34:00 -0400963 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Joe Perchesb6b38f72010-04-21 03:50:45 +0000965 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -0400966 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Jeff Layton13cfb732010-09-29 19:51:11 -0400968 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 for (total_written = 0; write_size > total_written;
973 total_written += bytes_written) {
974 rc = -EAGAIN;
975 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 /* we could deadlock if we called
978 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000979 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 server now */
Jeff Layton15886172010-10-15 15:33:59 -0400981 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (rc != 0)
983 break;
984 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000985 if (experimEnabled || (pTcon->ses->server &&
986 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +0000987 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +0000988 == 0))) {
Steve French3e844692005-10-03 13:37:24 -0700989 struct kvec iov[2];
990 unsigned int len;
991
Steve French0ae0efa2005-10-10 10:57:19 -0700992 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -0700993 write_size - total_written);
994 /* iov[0] is reserved for smb header */
995 iov[1].iov_base = (char *)write_data +
996 total_written;
997 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500998 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -0700999 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001000 *poffset, &bytes_written,
Jeff Layton77499812011-01-11 07:24:23 -05001001 iov, 1, 0);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001002 } else
Steve French60808232006-04-22 15:53:05 +00001003 rc = CIFSSMBWrite(xid, pTcon,
1004 open_file->netfid,
1005 min_t(const int, cifs_sb->wsize,
1006 write_size - total_written),
1007 *poffset, &bytes_written,
1008 write_data + total_written,
Jeff Layton77499812011-01-11 07:24:23 -05001009 NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 }
1011 if (rc || (bytes_written == 0)) {
1012 if (total_written)
1013 break;
1014 else {
1015 FreeXid(xid);
1016 return rc;
1017 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001018 } else {
1019 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023
Steve Frencha4544342005-08-24 13:59:35 -07001024 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Jeff Layton7da4b492010-10-15 15:34:00 -04001026 if (total_written > 0) {
1027 spin_lock(&dentry->d_inode->i_lock);
1028 if (*poffset > dentry->d_inode->i_size)
1029 i_size_write(dentry->d_inode, *poffset);
1030 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001032 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 FreeXid(xid);
1034 return total_written;
1035}
1036
Jeff Layton6508d902010-09-29 19:51:11 -04001037struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1038 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001039{
1040 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001041 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1042
1043 /* only filter by fsuid on multiuser mounts */
1044 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1045 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001046
Jeff Layton44772882010-10-15 15:34:03 -04001047 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001048 /* we could simply get the first_list_entry since write-only entries
1049 are always at the end of the list but since the first entry might
1050 have a close pending, we go through the whole list */
1051 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001052 if (fsuid_only && open_file->uid != current_fsuid())
1053 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001054 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001055 if (!open_file->invalidHandle) {
1056 /* found a good file */
1057 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001058 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001059 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001060 return open_file;
1061 } /* else might as well continue, and look for
1062 another, or simply have the caller reopen it
1063 again rather than trying to fix this handle */
1064 } else /* write only file */
1065 break; /* write only files are last so must be done */
1066 }
Jeff Layton44772882010-10-15 15:34:03 -04001067 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001068 return NULL;
1069}
Steve French630f3f0c2007-10-25 21:17:17 +00001070
Jeff Layton6508d902010-09-29 19:51:11 -04001071struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1072 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001073{
1074 struct cifsFileInfo *open_file;
Jeff Laytond3892292010-11-02 16:22:50 -04001075 struct cifs_sb_info *cifs_sb;
Jeff Layton2846d382008-09-22 21:33:33 -04001076 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001077 int rc;
Steve French6148a742005-10-05 12:23:19 -07001078
Steve French60808232006-04-22 15:53:05 +00001079 /* Having a null inode here (because mapping->host was set to zero by
1080 the VFS or MM) should not happen but we had reports of on oops (due to
1081 it being zero) during stress testcases so we need to check for it */
1082
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001083 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001084 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001085 dump_stack();
1086 return NULL;
1087 }
1088
Jeff Laytond3892292010-11-02 16:22:50 -04001089 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1090
Jeff Layton6508d902010-09-29 19:51:11 -04001091 /* only filter by fsuid on multiuser mounts */
1092 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1093 fsuid_only = false;
1094
Jeff Layton44772882010-10-15 15:34:03 -04001095 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001096refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001097 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001098 if (!any_available && open_file->pid != current->tgid)
1099 continue;
1100 if (fsuid_only && open_file->uid != current_fsuid())
1101 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001102 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001103 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001104
1105 if (!open_file->invalidHandle) {
1106 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001107 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001108 return open_file;
1109 }
Steve French8840dee2007-11-16 23:05:52 +00001110
Jeff Layton44772882010-10-15 15:34:03 -04001111 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001112
Steve French9b22b0b2007-10-02 01:11:08 +00001113 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001114 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001115 if (!rc)
1116 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001117
Steve Frenchcdff08e2010-10-21 22:46:14 +00001118 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001119 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001120 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001121
Steve Frenchcdff08e2010-10-21 22:46:14 +00001122 spin_lock(&cifs_file_list_lock);
1123
Steve French9b22b0b2007-10-02 01:11:08 +00001124 /* else we simply continue to the next entry. Thus
1125 we do not loop on reopen errors. If we
1126 can not reopen the file, for example if we
1127 reconnected to a server with another client
1128 racing to delete or lock the file we would not
1129 make progress if we restarted before the beginning
1130 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001131 }
1132 }
Jeff Layton2846d382008-09-22 21:33:33 -04001133 /* couldn't find useable FH with same pid, try any available */
1134 if (!any_available) {
1135 any_available = true;
1136 goto refind_writable;
1137 }
Jeff Layton44772882010-10-15 15:34:03 -04001138 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001139 return NULL;
1140}
1141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1143{
1144 struct address_space *mapping = page->mapping;
1145 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1146 char *write_data;
1147 int rc = -EFAULT;
1148 int bytes_written = 0;
1149 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001151 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 if (!mapping || !mapping->host)
1154 return -EFAULT;
1155
1156 inode = page->mapping->host;
1157 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 offset += (loff_t)from;
1160 write_data = kmap(page);
1161 write_data += from;
1162
1163 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1164 kunmap(page);
1165 return -EIO;
1166 }
1167
1168 /* racing with truncate? */
1169 if (offset > mapping->host->i_size) {
1170 kunmap(page);
1171 return 0; /* don't care */
1172 }
1173
1174 /* check to make sure that we are not extending the file */
1175 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001176 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Jeff Layton6508d902010-09-29 19:51:11 -04001178 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001179 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001180 bytes_written = cifs_write(open_file, write_data,
1181 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001182 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001184 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001185 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001186 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001187 else if (bytes_written < 0)
1188 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001189 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001190 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 rc = -EIO;
1192 }
1193
1194 kunmap(page);
1195 return rc;
1196}
1197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001199 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Steve French37c0eb42005-10-05 14:50:29 -07001201 unsigned int bytes_to_write;
1202 unsigned int bytes_written;
1203 struct cifs_sb_info *cifs_sb;
1204 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001205 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001206 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001207 int range_whole = 0;
1208 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001209 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001210 int n_iov = 0;
1211 pgoff_t next;
1212 int nr_pages;
1213 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001214 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001215 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001216 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001217 struct page *page;
1218 struct pagevec pvec;
1219 int rc = 0;
1220 int scanned = 0;
Jeff Layton77499812011-01-11 07:24:23 -05001221 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Steve French37c0eb42005-10-05 14:50:29 -07001223 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001224
Steve French37c0eb42005-10-05 14:50:29 -07001225 /*
1226 * If wsize is smaller that the page cache size, default to writing
1227 * one page at a time via cifs_writepage
1228 */
1229 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1230 return generic_writepages(mapping, wbc);
1231
Steve French9a0c8232007-02-02 04:21:57 +00001232 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001233 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001234 return generic_writepages(mapping, wbc);
1235
Steve French37c0eb42005-10-05 14:50:29 -07001236 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001237 * if there's no open file, then this is likely to fail too,
1238 * but it'll at least handle the return. Maybe it should be
1239 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001240 */
Jeff Layton6508d902010-09-29 19:51:11 -04001241 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001242 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001243 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001244 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001245 }
1246
Jeff Layton13cfb732010-09-29 19:51:11 -04001247 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001248 if (!experimEnabled && tcon->ses->server->secMode &
1249 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1250 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001251 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001252 return generic_writepages(mapping, wbc);
1253 }
1254 cifsFileInfo_put(open_file);
1255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 xid = GetXid();
1257
Steve French37c0eb42005-10-05 14:50:29 -07001258 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001259 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001260 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001261 end = -1;
1262 } else {
1263 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1264 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1265 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1266 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001267 scanned = 1;
1268 }
1269retry:
1270 while (!done && (index <= end) &&
1271 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1272 PAGECACHE_TAG_DIRTY,
1273 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1274 int first;
1275 unsigned int i;
1276
Steve French37c0eb42005-10-05 14:50:29 -07001277 first = -1;
1278 next = 0;
1279 n_iov = 0;
1280 bytes_to_write = 0;
1281
1282 for (i = 0; i < nr_pages; i++) {
1283 page = pvec.pages[i];
1284 /*
1285 * At this point we hold neither mapping->tree_lock nor
1286 * lock on the page itself: the page may be truncated or
1287 * invalidated (changing page->mapping to NULL), or even
1288 * swizzled back from swapper_space to tmpfs file
1289 * mapping
1290 */
1291
1292 if (first < 0)
1293 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001294 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001295 break;
1296
1297 if (unlikely(page->mapping != mapping)) {
1298 unlock_page(page);
1299 break;
1300 }
1301
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001302 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001303 done = 1;
1304 unlock_page(page);
1305 break;
1306 }
1307
1308 if (next && (page->index != next)) {
1309 /* Not next consecutive page */
1310 unlock_page(page);
1311 break;
1312 }
1313
1314 if (wbc->sync_mode != WB_SYNC_NONE)
1315 wait_on_page_writeback(page);
1316
1317 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001318 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001319 unlock_page(page);
1320 break;
1321 }
Steve French84d2f072005-10-12 15:32:05 -07001322
Linus Torvaldscb876f42006-12-23 16:19:07 -08001323 /*
1324 * This actually clears the dirty bit in the radix tree.
1325 * See cifs_writepage() for more commentary.
1326 */
1327 set_page_writeback(page);
1328
Steve French84d2f072005-10-12 15:32:05 -07001329 if (page_offset(page) >= mapping->host->i_size) {
1330 done = 1;
1331 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001332 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001333 break;
1334 }
1335
Steve French37c0eb42005-10-05 14:50:29 -07001336 /*
1337 * BB can we get rid of this? pages are held by pvec
1338 */
1339 page_cache_get(page);
1340
Steve French84d2f072005-10-12 15:32:05 -07001341 len = min(mapping->host->i_size - page_offset(page),
1342 (loff_t)PAGE_CACHE_SIZE);
1343
Steve French37c0eb42005-10-05 14:50:29 -07001344 /* reserve iov[0] for the smb header */
1345 n_iov++;
1346 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001347 iov[n_iov].iov_len = len;
1348 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001349
1350 if (first < 0) {
1351 first = i;
1352 offset = page_offset(page);
1353 }
1354 next = page->index + 1;
1355 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1356 break;
1357 }
1358 if (n_iov) {
Jeff Layton941b8532011-01-11 07:24:01 -05001359retry_write:
Jeff Layton6508d902010-09-29 19:51:11 -04001360 open_file = find_writable_file(CIFS_I(mapping->host),
1361 false);
Steve French23e7dd72005-10-20 13:44:56 -07001362 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001363 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001364 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001365 } else {
Jeff Laytonf3983c22010-09-22 16:17:40 -07001366 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001367 bytes_to_write, offset,
1368 &bytes_written, iov, n_iov,
Jeff Layton77499812011-01-11 07:24:23 -05001369 0);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001370 cifsFileInfo_put(open_file);
Steve French37c0eb42005-10-05 14:50:29 -07001371 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001372
Jeff Layton941b8532011-01-11 07:24:01 -05001373 cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
1374
1375 /*
1376 * For now, treat a short write as if nothing got
1377 * written. A zero length write however indicates
1378 * ENOSPC or EFBIG. We have no way to know which
1379 * though, so call it ENOSPC for now. EFBIG would
1380 * get translated to AS_EIO anyway.
1381 *
1382 * FIXME: make it take into account the data that did
1383 * get written
1384 */
1385 if (rc == 0) {
1386 if (bytes_written == 0)
1387 rc = -ENOSPC;
1388 else if (bytes_written < bytes_to_write)
1389 rc = -EAGAIN;
1390 }
1391
1392 /* retry on data-integrity flush */
1393 if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
1394 goto retry_write;
1395
1396 /* fix the stats and EOF */
1397 if (bytes_written > 0) {
Jeff Laytonf3983c22010-09-22 16:17:40 -07001398 cifs_stats_bytes_written(tcon, bytes_written);
Jeff Layton941b8532011-01-11 07:24:01 -05001399 cifs_update_eof(cifsi, offset, bytes_written);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001400 }
1401
Steve French37c0eb42005-10-05 14:50:29 -07001402 for (i = 0; i < n_iov; i++) {
1403 page = pvec.pages[first + i];
Jeff Layton941b8532011-01-11 07:24:01 -05001404 /* on retryable write error, redirty page */
1405 if (rc == -EAGAIN)
1406 redirty_page_for_writepage(wbc, page);
1407 else if (rc != 0)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001408 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001409 kunmap(page);
1410 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001411 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001412 page_cache_release(page);
1413 }
Jeff Layton941b8532011-01-11 07:24:01 -05001414
1415 if (rc != -EAGAIN)
1416 mapping_set_error(mapping, rc);
1417 else
1418 rc = 0;
1419
Steve French37c0eb42005-10-05 14:50:29 -07001420 if ((wbc->nr_to_write -= n_iov) <= 0)
1421 done = 1;
1422 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001423 } else
1424 /* Need to re-find the pages we skipped */
1425 index = pvec.pages[0]->index + 1;
1426
Steve French37c0eb42005-10-05 14:50:29 -07001427 pagevec_release(&pvec);
1428 }
1429 if (!scanned && !done) {
1430 /*
1431 * We hit the last page and there is more work to be done: wrap
1432 * back to the start of the file
1433 */
1434 scanned = 1;
1435 index = 0;
1436 goto retry;
1437 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001438 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001439 mapping->writeback_index = index;
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001442 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 return rc;
1444}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001446static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447{
1448 int rc = -EFAULT;
1449 int xid;
1450
1451 xid = GetXid();
1452/* BB add check for wbc flags */
1453 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001454 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001455 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001456
1457 /*
1458 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1459 *
1460 * A writepage() implementation always needs to do either this,
1461 * or re-dirty the page with "redirty_page_for_writepage()" in
1462 * the case of a failure.
1463 *
1464 * Just unlocking the page will cause the radix tree tag-bits
1465 * to fail to update with the state of the page correctly.
1466 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001467 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1469 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1470 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001471 end_page_writeback(page);
1472 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 FreeXid(xid);
1474 return rc;
1475}
1476
Nick Piggind9414772008-09-24 11:32:59 -04001477static int cifs_write_end(struct file *file, struct address_space *mapping,
1478 loff_t pos, unsigned len, unsigned copied,
1479 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
Nick Piggind9414772008-09-24 11:32:59 -04001481 int rc;
1482 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Joe Perchesb6b38f72010-04-21 03:50:45 +00001484 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1485 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001486
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001487 if (PageChecked(page)) {
1488 if (copied == len)
1489 SetPageUptodate(page);
1490 ClearPageChecked(page);
1491 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001492 SetPageUptodate(page);
1493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001495 char *page_data;
1496 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1497 int xid;
1498
1499 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 /* this is probably better than directly calling
1501 partialpage_write since in this function the file handle is
1502 known which we might as well leverage */
1503 /* BB check if anything else missing out of ppw
1504 such as updating last write time */
1505 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001506 rc = cifs_write(file->private_data, page_data + offset,
1507 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001508 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001510
1511 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001512 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001513 rc = copied;
1514 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 set_page_dirty(page);
1516 }
1517
Nick Piggind9414772008-09-24 11:32:59 -04001518 if (rc > 0) {
1519 spin_lock(&inode->i_lock);
1520 if (pos > inode->i_size)
1521 i_size_write(inode, pos);
1522 spin_unlock(&inode->i_lock);
1523 }
1524
1525 unlock_page(page);
1526 page_cache_release(page);
1527
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 return rc;
1529}
1530
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001531int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 int xid;
1534 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001535 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001536 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001537 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539 xid = GetXid();
1540
Joe Perchesb6b38f72010-04-21 03:50:45 +00001541 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001542 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001543
Jeff Laytoncea21802007-11-20 23:19:03 +00001544 rc = filemap_write_and_wait(inode->i_mapping);
1545 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001546 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1547
Jeff Layton13cfb732010-09-29 19:51:11 -04001548 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001549 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001550 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001551 }
Steve Frenchb298f222009-02-21 21:17:43 +00001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 FreeXid(xid);
1554 return rc;
1555}
1556
NeilBrown3978d7172006-03-26 01:37:17 -08001557/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
1559 struct address_space *mapping;
1560 struct inode *inode;
1561 unsigned long index = page->index;
1562 unsigned int rpages = 0;
1563 int rc = 0;
1564
Steve Frenchf19159d2010-04-21 04:12:10 +00001565 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 mapping = page->mapping;
1567 if (!mapping)
1568 return 0;
1569 inode = mapping->host;
1570 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001571 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001573/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1575
Joe Perchesb6b38f72010-04-21 03:50:45 +00001576/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
NeilBrown3978d7172006-03-26 01:37:17 -08001578#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 if (rc < 0)
1580 return rc;
1581 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001582#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583} */
1584
1585/*
1586 * As file closes, flush all cached write data for this inode checking
1587 * for write behind errors.
1588 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001589int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001591 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 int rc = 0;
1593
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001594 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001595 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001596
Joe Perchesb6b38f72010-04-21 03:50:45 +00001597 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 return rc;
1600}
1601
1602ssize_t cifs_user_read(struct file *file, char __user *read_data,
1603 size_t read_size, loff_t *poffset)
1604{
1605 int rc = -EACCES;
1606 unsigned int bytes_read = 0;
1607 unsigned int total_read = 0;
1608 unsigned int current_read_size;
1609 struct cifs_sb_info *cifs_sb;
1610 struct cifsTconInfo *pTcon;
1611 int xid;
1612 struct cifsFileInfo *open_file;
1613 char *smb_read_data;
1614 char __user *current_offset;
1615 struct smb_com_read_rsp *pSMBr;
1616
1617 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001618 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301621 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301623 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001625 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001626 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Steve Frenchad7a2922008-02-07 23:25:02 +00001628 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001629 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 for (total_read = 0, current_offset = read_data;
1632 read_size > total_read;
1633 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001634 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 cifs_sb->rsize);
1636 rc = -EAGAIN;
1637 smb_read_data = NULL;
1638 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001639 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001640 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001641 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 if (rc != 0)
1643 break;
1644 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001645 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001646 open_file->netfid,
1647 current_read_size, *poffset,
1648 &bytes_read, &smb_read_data,
1649 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001652 if (copy_to_user(current_offset,
1653 smb_read_data +
1654 4 /* RFC1001 length field */ +
1655 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001656 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001657 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001658
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001659 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001660 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001661 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001662 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 smb_read_data = NULL;
1664 }
1665 }
1666 if (rc || (bytes_read == 0)) {
1667 if (total_read) {
1668 break;
1669 } else {
1670 FreeXid(xid);
1671 return rc;
1672 }
1673 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001674 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 *poffset += bytes_read;
1676 }
1677 }
1678 FreeXid(xid);
1679 return total_read;
1680}
1681
1682
1683static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1684 loff_t *poffset)
1685{
1686 int rc = -EACCES;
1687 unsigned int bytes_read = 0;
1688 unsigned int total_read;
1689 unsigned int current_read_size;
1690 struct cifs_sb_info *cifs_sb;
1691 struct cifsTconInfo *pTcon;
1692 int xid;
1693 char *current_offset;
1694 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001695 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001698 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301701 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301703 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001705 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001706 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001709 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001711 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 read_size > total_read;
1713 total_read += bytes_read, current_offset += bytes_read) {
1714 current_read_size = min_t(const int, read_size - total_read,
1715 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001716 /* For windows me and 9x we do not want to request more
1717 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001718 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001719 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1720 current_read_size = min_t(const int, current_read_size,
1721 pTcon->ses->server->maxBuf - 128);
1722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 rc = -EAGAIN;
1724 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001725 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001726 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc != 0)
1728 break;
1729 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001730 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001731 open_file->netfid,
1732 current_read_size, *poffset,
1733 &bytes_read, &current_offset,
1734 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 if (rc || (bytes_read == 0)) {
1737 if (total_read) {
1738 break;
1739 } else {
1740 FreeXid(xid);
1741 return rc;
1742 }
1743 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001744 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 *poffset += bytes_read;
1746 }
1747 }
1748 FreeXid(xid);
1749 return total_read;
1750}
1751
1752int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1753{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 int rc, xid;
1755
1756 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001757 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001759 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 FreeXid(xid);
1761 return rc;
1762 }
1763 rc = generic_file_mmap(file, vma);
1764 FreeXid(xid);
1765 return rc;
1766}
1767
1768
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001769static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001770 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 struct page *page;
1773 char *target;
1774
1775 while (bytes_read > 0) {
1776 if (list_empty(pages))
1777 break;
1778
1779 page = list_entry(pages->prev, struct page, lru);
1780 list_del(&page->lru);
1781
Nick Piggin315e9952010-04-21 03:18:28 +00001782 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 GFP_KERNEL)) {
1784 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001785 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001786 data += PAGE_CACHE_SIZE;
1787 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 continue;
1789 }
Jeff Layton06b43672010-06-01 10:54:45 -04001790 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001792 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 if (PAGE_CACHE_SIZE > bytes_read) {
1795 memcpy(target, data, bytes_read);
1796 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001797 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 PAGE_CACHE_SIZE - bytes_read);
1799 bytes_read = 0;
1800 } else {
1801 memcpy(target, data, PAGE_CACHE_SIZE);
1802 bytes_read -= PAGE_CACHE_SIZE;
1803 }
1804 kunmap_atomic(target, KM_USER0);
1805
1806 flush_dcache_page(page);
1807 SetPageUptodate(page);
1808 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301810
1811 /* add page to FS-Cache */
1812 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 }
1814 return;
1815}
1816
1817static int cifs_readpages(struct file *file, struct address_space *mapping,
1818 struct list_head *page_list, unsigned num_pages)
1819{
1820 int rc = -EACCES;
1821 int xid;
1822 loff_t offset;
1823 struct page *page;
1824 struct cifs_sb_info *cifs_sb;
1825 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001826 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001827 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 char *smb_read_data = NULL;
1829 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001831 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
1833 xid = GetXid();
1834 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301835 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301837 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001839 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001840 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001841 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001842
Suresh Jayaraman56698232010-07-05 18:13:25 +05301843 /*
1844 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1845 * immediately if the cookie is negative
1846 */
1847 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1848 &num_pages);
1849 if (rc == 0)
1850 goto read_complete;
1851
Steve Frenchf19159d2010-04-21 04:12:10 +00001852 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 for (i = 0; i < num_pages; ) {
1854 unsigned contig_pages;
1855 struct page *tmp_page;
1856 unsigned long expected_index;
1857
1858 if (list_empty(page_list))
1859 break;
1860
1861 page = list_entry(page_list->prev, struct page, lru);
1862 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1863
1864 /* count adjacent pages that we will read into */
1865 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001866 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001868 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (tmp_page->index == expected_index) {
1870 contig_pages++;
1871 expected_index++;
1872 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001873 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 }
1875 if (contig_pages + i > num_pages)
1876 contig_pages = num_pages - i;
1877
1878 /* for reads over a certain size could initiate async
1879 read ahead */
1880
1881 read_size = contig_pages * PAGE_CACHE_SIZE;
1882 /* Read size needs to be in multiples of one page */
1883 read_size = min_t(const unsigned int, read_size,
1884 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001885 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1886 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 rc = -EAGAIN;
1888 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001889 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001890 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (rc != 0)
1892 break;
1893 }
1894
Steve Frenchbfa0d752005-08-31 21:50:37 -07001895 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001896 open_file->netfid,
1897 read_size, offset,
1898 &bytes_read, &smb_read_data,
1899 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001900 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001901 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001903 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001904 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001905 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001906 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 smb_read_data = NULL;
1908 }
1909 }
1910 }
1911 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001912 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 break;
1914 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001915 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1917 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1918 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001919 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001922 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001923 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 i++; /* account for partial page */
1925
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001926 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001928 /* BB do we need to verify this common case ?
1929 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 we will hit it on next read */
1931
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001932 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
1934 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001935 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001936 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001937 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001938 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 break;
1941 }
1942 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001943 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001944 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001945 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001946 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 smb_read_data = NULL;
1948 }
1949 bytes_read = 0;
1950 }
1951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952/* need to free smb_read_data buf before exit */
1953 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001954 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001955 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001956 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001957 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Suresh Jayaraman56698232010-07-05 18:13:25 +05301961read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 FreeXid(xid);
1963 return rc;
1964}
1965
1966static int cifs_readpage_worker(struct file *file, struct page *page,
1967 loff_t *poffset)
1968{
1969 char *read_data;
1970 int rc;
1971
Suresh Jayaraman56698232010-07-05 18:13:25 +05301972 /* Is the page cached? */
1973 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
1974 if (rc == 0)
1975 goto read_complete;
1976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 page_cache_get(page);
1978 read_data = kmap(page);
1979 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001982
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 if (rc < 0)
1984 goto io_error;
1985 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001986 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001988 file->f_path.dentry->d_inode->i_atime =
1989 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001990
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 if (PAGE_CACHE_SIZE > rc)
1992 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
1993
1994 flush_dcache_page(page);
1995 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301996
1997 /* send this page to the cache */
1998 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
1999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002003 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302005
2006read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 return rc;
2008}
2009
2010static int cifs_readpage(struct file *file, struct page *page)
2011{
2012 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2013 int rc = -EACCES;
2014 int xid;
2015
2016 xid = GetXid();
2017
2018 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302019 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302021 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 }
2023
Joe Perchesb6b38f72010-04-21 03:50:45 +00002024 cFYI(1, "readpage %p at offset %d 0x%x\n",
2025 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
2027 rc = cifs_readpage_worker(file, page, &offset);
2028
2029 unlock_page(page);
2030
2031 FreeXid(xid);
2032 return rc;
2033}
2034
Steve Frencha403a0a2007-07-26 15:54:16 +00002035static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2036{
2037 struct cifsFileInfo *open_file;
2038
Jeff Layton44772882010-10-15 15:34:03 -04002039 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002040 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002041 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002042 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002043 return 1;
2044 }
2045 }
Jeff Layton44772882010-10-15 15:34:03 -04002046 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002047 return 0;
2048}
2049
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050/* We do not want to update the file size from server for inodes
2051 open for write - to avoid races with writepage extending
2052 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002053 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 but this is tricky to do without racing with writebehind
2055 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002056bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
Steve Frencha403a0a2007-07-26 15:54:16 +00002058 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002059 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002060
Steve Frencha403a0a2007-07-26 15:54:16 +00002061 if (is_inode_writable(cifsInode)) {
2062 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002063 struct cifs_sb_info *cifs_sb;
2064
Steve Frenchc32a0b62006-01-12 14:41:28 -08002065 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002066 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002067 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002068 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002069 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002070 }
2071
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002072 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002073 return true;
Steve French7ba52632007-02-08 18:14:13 +00002074
Steve French4b18f2a2008-04-29 00:06:05 +00002075 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002076 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002077 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078}
2079
Nick Piggind9414772008-09-24 11:32:59 -04002080static int cifs_write_begin(struct file *file, struct address_space *mapping,
2081 loff_t pos, unsigned len, unsigned flags,
2082 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083{
Nick Piggind9414772008-09-24 11:32:59 -04002084 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2085 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002086 loff_t page_start = pos & PAGE_MASK;
2087 loff_t i_size;
2088 struct page *page;
2089 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Joe Perchesb6b38f72010-04-21 03:50:45 +00002091 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002092
Nick Piggin54566b22009-01-04 12:00:53 -08002093 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002094 if (!page) {
2095 rc = -ENOMEM;
2096 goto out;
2097 }
Nick Piggind9414772008-09-24 11:32:59 -04002098
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002099 if (PageUptodate(page))
2100 goto out;
Steve French8a236262007-03-06 00:31:00 +00002101
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002102 /*
2103 * If we write a full page it will be up to date, no need to read from
2104 * the server. If the write is short, we'll end up doing a sync write
2105 * instead.
2106 */
2107 if (len == PAGE_CACHE_SIZE)
2108 goto out;
2109
2110 /*
2111 * optimize away the read when we have an oplock, and we're not
2112 * expecting to use any of the data we'd be reading in. That
2113 * is, when the page lies beyond the EOF, or straddles the EOF
2114 * and the write will cover all of the existing data.
2115 */
2116 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2117 i_size = i_size_read(mapping->host);
2118 if (page_start >= i_size ||
2119 (offset == 0 && (pos + len) >= i_size)) {
2120 zero_user_segments(page, 0, offset,
2121 offset + len,
2122 PAGE_CACHE_SIZE);
2123 /*
2124 * PageChecked means that the parts of the page
2125 * to which we're not writing are considered up
2126 * to date. Once the data is copied to the
2127 * page, it can be set uptodate.
2128 */
2129 SetPageChecked(page);
2130 goto out;
2131 }
2132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Nick Piggind9414772008-09-24 11:32:59 -04002134 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002135 /*
2136 * might as well read a page, it is fast enough. If we get
2137 * an error, we don't need to return it. cifs_write_end will
2138 * do a sync write instead since PG_uptodate isn't set.
2139 */
2140 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002141 } else {
2142 /* we could try using another file handle if there is one -
2143 but how would we lock it to prevent close of that handle
2144 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002145 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002146 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002147out:
2148 *pagep = page;
2149 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150}
2151
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302152static int cifs_release_page(struct page *page, gfp_t gfp)
2153{
2154 if (PagePrivate(page))
2155 return 0;
2156
2157 return cifs_fscache_release_page(page, gfp);
2158}
2159
2160static void cifs_invalidate_page(struct page *page, unsigned long offset)
2161{
2162 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2163
2164 if (offset == 0)
2165 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2166}
2167
Tejun Heo9b646972010-07-20 22:09:02 +02002168void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002169{
2170 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2171 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002172 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002173 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002174 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002175
2176 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002177 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002178 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002179 else
Al Viro8737c932009-12-24 06:47:55 -05002180 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002181 rc = filemap_fdatawrite(inode->i_mapping);
2182 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002183 rc = filemap_fdatawait(inode->i_mapping);
2184 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002185 invalidate_remote_inode(inode);
2186 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002187 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002188 }
2189
2190 /*
2191 * releasing stale oplock after recent reconnect of smb session using
2192 * a now incorrect file handle is not a data integrity issue but do
2193 * not bother sending an oplock release if session to server still is
2194 * disconnected since oplock already released by the server
2195 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002196 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002197 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002198 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
2199 cinode->clientCanCacheRead ? 1 : 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002200 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002201 }
Tejun Heo9b646972010-07-20 22:09:02 +02002202
2203 /*
2204 * We might have kicked in before is_valid_oplock_break()
2205 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302206 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002207 */
Jeff Layton44772882010-10-15 15:34:03 -04002208 spin_lock(&cifs_file_list_lock);
2209 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002210
2211 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002212}
2213
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002214/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002215void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002216{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002217 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002218 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002219}
2220
Tejun Heo9b646972010-07-20 22:09:02 +02002221void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002222{
Jeff Laytonebe2e912010-11-10 10:19:10 -05002223 struct super_block *sb = cfile->dentry->d_sb;
2224
Jeff Layton3bc303c2009-09-21 06:47:50 -04002225 cifsFileInfo_put(cfile);
Jeff Laytonebe2e912010-11-10 10:19:10 -05002226 cifs_sb_deactive(sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002227}
2228
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002229const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 .readpage = cifs_readpage,
2231 .readpages = cifs_readpages,
2232 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002233 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002234 .write_begin = cifs_write_begin,
2235 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302237 .releasepage = cifs_release_page,
2238 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 /* .sync_page = cifs_sync_page, */
2240 /* .direct_IO = */
2241};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002242
2243/*
2244 * cifs_readpages requires the server to support a buffer large enough to
2245 * contain the header plus one complete page of data. Otherwise, we need
2246 * to leave cifs_readpages out of the address space operations.
2247 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002248const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002249 .readpage = cifs_readpage,
2250 .writepage = cifs_writepage,
2251 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002252 .write_begin = cifs_write_begin,
2253 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002254 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302255 .releasepage = cifs_release_page,
2256 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002257 /* .sync_page = cifs_sync_page, */
2258 /* .direct_IO = */
2259};