blob: 5790fab7349be0226b6f631b07d4a081bcd1f4cc [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
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +03001531int cifs_strict_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;
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +03001538 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540 xid = GetXid();
1541
Joe Perchesb6b38f72010-04-21 03:50:45 +00001542 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001543 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001544
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +03001545 if (!CIFS_I(inode)->clientCanCacheRead)
1546 cifs_invalidate_mapping(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001547
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +03001548 tcon = tlink_tcon(smbfile->tlink);
1549 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
1550 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
1551
1552 FreeXid(xid);
1553 return rc;
1554}
1555
1556int cifs_fsync(struct file *file, int datasync)
1557{
1558 int xid;
1559 int rc = 0;
1560 struct cifsTconInfo *tcon;
1561 struct cifsFileInfo *smbfile = file->private_data;
1562 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1563
1564 xid = GetXid();
1565
1566 cFYI(1, "Sync file - name: %s datasync: 0x%x",
1567 file->f_path.dentry->d_name.name, datasync);
1568
1569 tcon = tlink_tcon(smbfile->tlink);
1570 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
1571 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Steve Frenchb298f222009-02-21 21:17:43 +00001572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 FreeXid(xid);
1574 return rc;
1575}
1576
NeilBrown3978d7172006-03-26 01:37:17 -08001577/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578{
1579 struct address_space *mapping;
1580 struct inode *inode;
1581 unsigned long index = page->index;
1582 unsigned int rpages = 0;
1583 int rc = 0;
1584
Steve Frenchf19159d2010-04-21 04:12:10 +00001585 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 mapping = page->mapping;
1587 if (!mapping)
1588 return 0;
1589 inode = mapping->host;
1590 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001591 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001593/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1595
Joe Perchesb6b38f72010-04-21 03:50:45 +00001596/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
NeilBrown3978d7172006-03-26 01:37:17 -08001598#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc < 0)
1600 return rc;
1601 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001602#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603} */
1604
1605/*
1606 * As file closes, flush all cached write data for this inode checking
1607 * for write behind errors.
1608 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001609int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001611 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 int rc = 0;
1613
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001614 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001615 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001616
Joe Perchesb6b38f72010-04-21 03:50:45 +00001617 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 return rc;
1620}
1621
1622ssize_t cifs_user_read(struct file *file, char __user *read_data,
1623 size_t read_size, loff_t *poffset)
1624{
1625 int rc = -EACCES;
1626 unsigned int bytes_read = 0;
1627 unsigned int total_read = 0;
1628 unsigned int current_read_size;
1629 struct cifs_sb_info *cifs_sb;
1630 struct cifsTconInfo *pTcon;
1631 int xid;
1632 struct cifsFileInfo *open_file;
1633 char *smb_read_data;
1634 char __user *current_offset;
1635 struct smb_com_read_rsp *pSMBr;
1636
1637 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001638 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301641 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301643 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001645 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001646 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Steve Frenchad7a2922008-02-07 23:25:02 +00001648 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001649 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001650
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 for (total_read = 0, current_offset = read_data;
1652 read_size > total_read;
1653 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001654 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 cifs_sb->rsize);
1656 rc = -EAGAIN;
1657 smb_read_data = NULL;
1658 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001659 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001660 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001661 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (rc != 0)
1663 break;
1664 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001665 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001666 open_file->netfid,
1667 current_read_size, *poffset,
1668 &bytes_read, &smb_read_data,
1669 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001672 if (copy_to_user(current_offset,
1673 smb_read_data +
1674 4 /* RFC1001 length field */ +
1675 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001676 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001677 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001678
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001679 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001680 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001681 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001682 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 smb_read_data = NULL;
1684 }
1685 }
1686 if (rc || (bytes_read == 0)) {
1687 if (total_read) {
1688 break;
1689 } else {
1690 FreeXid(xid);
1691 return rc;
1692 }
1693 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001694 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 *poffset += bytes_read;
1696 }
1697 }
1698 FreeXid(xid);
1699 return total_read;
1700}
1701
1702
1703static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1704 loff_t *poffset)
1705{
1706 int rc = -EACCES;
1707 unsigned int bytes_read = 0;
1708 unsigned int total_read;
1709 unsigned int current_read_size;
1710 struct cifs_sb_info *cifs_sb;
1711 struct cifsTconInfo *pTcon;
1712 int xid;
1713 char *current_offset;
1714 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001715 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001718 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301721 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301723 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001725 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001726 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001729 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001731 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 read_size > total_read;
1733 total_read += bytes_read, current_offset += bytes_read) {
1734 current_read_size = min_t(const int, read_size - total_read,
1735 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001736 /* For windows me and 9x we do not want to request more
1737 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001738 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001739 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1740 current_read_size = min_t(const int, current_read_size,
1741 pTcon->ses->server->maxBuf - 128);
1742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 rc = -EAGAIN;
1744 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001745 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001746 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 if (rc != 0)
1748 break;
1749 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001750 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001751 open_file->netfid,
1752 current_read_size, *poffset,
1753 &bytes_read, &current_offset,
1754 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 }
1756 if (rc || (bytes_read == 0)) {
1757 if (total_read) {
1758 break;
1759 } else {
1760 FreeXid(xid);
1761 return rc;
1762 }
1763 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001764 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 *poffset += bytes_read;
1766 }
1767 }
1768 FreeXid(xid);
1769 return total_read;
1770}
1771
1772int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1773{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 int rc, xid;
1775
1776 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001777 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001779 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 FreeXid(xid);
1781 return rc;
1782 }
1783 rc = generic_file_mmap(file, vma);
1784 FreeXid(xid);
1785 return rc;
1786}
1787
1788
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001790 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791{
1792 struct page *page;
1793 char *target;
1794
1795 while (bytes_read > 0) {
1796 if (list_empty(pages))
1797 break;
1798
1799 page = list_entry(pages->prev, struct page, lru);
1800 list_del(&page->lru);
1801
Nick Piggin315e9952010-04-21 03:18:28 +00001802 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 GFP_KERNEL)) {
1804 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001805 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001806 data += PAGE_CACHE_SIZE;
1807 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 continue;
1809 }
Jeff Layton06b43672010-06-01 10:54:45 -04001810 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001812 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
1814 if (PAGE_CACHE_SIZE > bytes_read) {
1815 memcpy(target, data, bytes_read);
1816 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001817 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 PAGE_CACHE_SIZE - bytes_read);
1819 bytes_read = 0;
1820 } else {
1821 memcpy(target, data, PAGE_CACHE_SIZE);
1822 bytes_read -= PAGE_CACHE_SIZE;
1823 }
1824 kunmap_atomic(target, KM_USER0);
1825
1826 flush_dcache_page(page);
1827 SetPageUptodate(page);
1828 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301830
1831 /* add page to FS-Cache */
1832 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 }
1834 return;
1835}
1836
1837static int cifs_readpages(struct file *file, struct address_space *mapping,
1838 struct list_head *page_list, unsigned num_pages)
1839{
1840 int rc = -EACCES;
1841 int xid;
1842 loff_t offset;
1843 struct page *page;
1844 struct cifs_sb_info *cifs_sb;
1845 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001846 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001847 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 char *smb_read_data = NULL;
1849 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001851 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 xid = GetXid();
1854 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301855 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301857 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001859 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001860 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001861 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001862
Suresh Jayaraman56698232010-07-05 18:13:25 +05301863 /*
1864 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1865 * immediately if the cookie is negative
1866 */
1867 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1868 &num_pages);
1869 if (rc == 0)
1870 goto read_complete;
1871
Steve Frenchf19159d2010-04-21 04:12:10 +00001872 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 for (i = 0; i < num_pages; ) {
1874 unsigned contig_pages;
1875 struct page *tmp_page;
1876 unsigned long expected_index;
1877
1878 if (list_empty(page_list))
1879 break;
1880
1881 page = list_entry(page_list->prev, struct page, lru);
1882 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1883
1884 /* count adjacent pages that we will read into */
1885 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001886 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001888 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (tmp_page->index == expected_index) {
1890 contig_pages++;
1891 expected_index++;
1892 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001893 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895 if (contig_pages + i > num_pages)
1896 contig_pages = num_pages - i;
1897
1898 /* for reads over a certain size could initiate async
1899 read ahead */
1900
1901 read_size = contig_pages * PAGE_CACHE_SIZE;
1902 /* Read size needs to be in multiples of one page */
1903 read_size = min_t(const unsigned int, read_size,
1904 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001905 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1906 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 rc = -EAGAIN;
1908 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001909 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001910 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (rc != 0)
1912 break;
1913 }
1914
Steve Frenchbfa0d752005-08-31 21:50:37 -07001915 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001916 open_file->netfid,
1917 read_size, offset,
1918 &bytes_read, &smb_read_data,
1919 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001920 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001921 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001923 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001924 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001925 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001926 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 smb_read_data = NULL;
1928 }
1929 }
1930 }
1931 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001932 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 break;
1934 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001935 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1937 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1938 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001939 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001942 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001943 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 i++; /* account for partial page */
1945
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001946 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001948 /* BB do we need to verify this common case ?
1949 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 we will hit it on next read */
1951
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001952 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 }
1954 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001955 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001956 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001957 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001958 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961 }
1962 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001963 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001964 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001965 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001966 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 smb_read_data = NULL;
1968 }
1969 bytes_read = 0;
1970 }
1971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972/* need to free smb_read_data buf before exit */
1973 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001974 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001975 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08001977 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Suresh Jayaraman56698232010-07-05 18:13:25 +05301981read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 FreeXid(xid);
1983 return rc;
1984}
1985
1986static int cifs_readpage_worker(struct file *file, struct page *page,
1987 loff_t *poffset)
1988{
1989 char *read_data;
1990 int rc;
1991
Suresh Jayaraman56698232010-07-05 18:13:25 +05301992 /* Is the page cached? */
1993 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
1994 if (rc == 0)
1995 goto read_complete;
1996
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 page_cache_get(page);
1998 read_data = kmap(page);
1999 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 if (rc < 0)
2004 goto io_error;
2005 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002006 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002007
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002008 file->f_path.dentry->d_inode->i_atime =
2009 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (PAGE_CACHE_SIZE > rc)
2012 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2013
2014 flush_dcache_page(page);
2015 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302016
2017 /* send this page to the cache */
2018 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2019
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002021
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002023 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302025
2026read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return rc;
2028}
2029
2030static int cifs_readpage(struct file *file, struct page *page)
2031{
2032 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2033 int rc = -EACCES;
2034 int xid;
2035
2036 xid = GetXid();
2037
2038 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302039 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302041 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043
Joe Perchesb6b38f72010-04-21 03:50:45 +00002044 cFYI(1, "readpage %p at offset %d 0x%x\n",
2045 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
2047 rc = cifs_readpage_worker(file, page, &offset);
2048
2049 unlock_page(page);
2050
2051 FreeXid(xid);
2052 return rc;
2053}
2054
Steve Frencha403a0a2007-07-26 15:54:16 +00002055static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2056{
2057 struct cifsFileInfo *open_file;
2058
Jeff Layton44772882010-10-15 15:34:03 -04002059 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002060 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002061 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002062 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002063 return 1;
2064 }
2065 }
Jeff Layton44772882010-10-15 15:34:03 -04002066 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002067 return 0;
2068}
2069
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070/* We do not want to update the file size from server for inodes
2071 open for write - to avoid races with writepage extending
2072 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002073 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 but this is tricky to do without racing with writebehind
2075 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002076bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
Steve Frencha403a0a2007-07-26 15:54:16 +00002078 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002079 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002080
Steve Frencha403a0a2007-07-26 15:54:16 +00002081 if (is_inode_writable(cifsInode)) {
2082 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002083 struct cifs_sb_info *cifs_sb;
2084
Steve Frenchc32a0b62006-01-12 14:41:28 -08002085 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002086 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002087 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002088 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002089 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002090 }
2091
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002093 return true;
Steve French7ba52632007-02-08 18:14:13 +00002094
Steve French4b18f2a2008-04-29 00:06:05 +00002095 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002096 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002097 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098}
2099
Nick Piggind9414772008-09-24 11:32:59 -04002100static int cifs_write_begin(struct file *file, struct address_space *mapping,
2101 loff_t pos, unsigned len, unsigned flags,
2102 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
Nick Piggind9414772008-09-24 11:32:59 -04002104 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2105 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002106 loff_t page_start = pos & PAGE_MASK;
2107 loff_t i_size;
2108 struct page *page;
2109 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Joe Perchesb6b38f72010-04-21 03:50:45 +00002111 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002112
Nick Piggin54566b22009-01-04 12:00:53 -08002113 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002114 if (!page) {
2115 rc = -ENOMEM;
2116 goto out;
2117 }
Nick Piggind9414772008-09-24 11:32:59 -04002118
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002119 if (PageUptodate(page))
2120 goto out;
Steve French8a236262007-03-06 00:31:00 +00002121
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002122 /*
2123 * If we write a full page it will be up to date, no need to read from
2124 * the server. If the write is short, we'll end up doing a sync write
2125 * instead.
2126 */
2127 if (len == PAGE_CACHE_SIZE)
2128 goto out;
2129
2130 /*
2131 * optimize away the read when we have an oplock, and we're not
2132 * expecting to use any of the data we'd be reading in. That
2133 * is, when the page lies beyond the EOF, or straddles the EOF
2134 * and the write will cover all of the existing data.
2135 */
2136 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2137 i_size = i_size_read(mapping->host);
2138 if (page_start >= i_size ||
2139 (offset == 0 && (pos + len) >= i_size)) {
2140 zero_user_segments(page, 0, offset,
2141 offset + len,
2142 PAGE_CACHE_SIZE);
2143 /*
2144 * PageChecked means that the parts of the page
2145 * to which we're not writing are considered up
2146 * to date. Once the data is copied to the
2147 * page, it can be set uptodate.
2148 */
2149 SetPageChecked(page);
2150 goto out;
2151 }
2152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Nick Piggind9414772008-09-24 11:32:59 -04002154 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002155 /*
2156 * might as well read a page, it is fast enough. If we get
2157 * an error, we don't need to return it. cifs_write_end will
2158 * do a sync write instead since PG_uptodate isn't set.
2159 */
2160 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002161 } else {
2162 /* we could try using another file handle if there is one -
2163 but how would we lock it to prevent close of that handle
2164 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002165 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002166 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002167out:
2168 *pagep = page;
2169 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170}
2171
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302172static int cifs_release_page(struct page *page, gfp_t gfp)
2173{
2174 if (PagePrivate(page))
2175 return 0;
2176
2177 return cifs_fscache_release_page(page, gfp);
2178}
2179
2180static void cifs_invalidate_page(struct page *page, unsigned long offset)
2181{
2182 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2183
2184 if (offset == 0)
2185 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2186}
2187
Tejun Heo9b646972010-07-20 22:09:02 +02002188void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002189{
2190 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2191 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002192 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002193 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002194 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002195
2196 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002197 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002198 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002199 else
Al Viro8737c932009-12-24 06:47:55 -05002200 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002201 rc = filemap_fdatawrite(inode->i_mapping);
2202 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002203 rc = filemap_fdatawait(inode->i_mapping);
2204 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002205 invalidate_remote_inode(inode);
2206 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002207 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002208 }
2209
2210 /*
2211 * releasing stale oplock after recent reconnect of smb session using
2212 * a now incorrect file handle is not a data integrity issue but do
2213 * not bother sending an oplock release if session to server still is
2214 * disconnected since oplock already released by the server
2215 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002216 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002217 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002218 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
2219 cinode->clientCanCacheRead ? 1 : 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002220 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002221 }
Tejun Heo9b646972010-07-20 22:09:02 +02002222
2223 /*
2224 * We might have kicked in before is_valid_oplock_break()
2225 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302226 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002227 */
Jeff Layton44772882010-10-15 15:34:03 -04002228 spin_lock(&cifs_file_list_lock);
2229 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002230
2231 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002232}
2233
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002234/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002235void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002236{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002237 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002238 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002239}
2240
Tejun Heo9b646972010-07-20 22:09:02 +02002241void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002242{
Jeff Laytonebe2e912010-11-10 10:19:10 -05002243 struct super_block *sb = cfile->dentry->d_sb;
2244
Jeff Layton3bc303c2009-09-21 06:47:50 -04002245 cifsFileInfo_put(cfile);
Jeff Laytonebe2e912010-11-10 10:19:10 -05002246 cifs_sb_deactive(sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002247}
2248
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002249const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 .readpage = cifs_readpage,
2251 .readpages = cifs_readpages,
2252 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002253 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002254 .write_begin = cifs_write_begin,
2255 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302257 .releasepage = cifs_release_page,
2258 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 /* .sync_page = cifs_sync_page, */
2260 /* .direct_IO = */
2261};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002262
2263/*
2264 * cifs_readpages requires the server to support a buffer large enough to
2265 * contain the header plus one complete page of data. Otherwise, we need
2266 * to leave cifs_readpages out of the address space operations.
2267 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002268const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002269 .readpage = cifs_readpage,
2270 .writepage = cifs_writepage,
2271 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002272 .write_begin = cifs_write_begin,
2273 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002274 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302275 .releasepage = cifs_release_page,
2276 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002277 /* .sync_page = cifs_sync_page, */
2278 /* .direct_IO = */
2279};