blob: a566f155df491c90bec56a6e985feb85824112ed [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
Steve Frenchf19159d2010-04-21 04:12:10 +00006 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include "cifsfs.h"
37#include "cifspdu.h"
38#include "cifsglob.h"
39#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42#include "cifs_fs_sb.h"
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +053043#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static inline int cifs_convert_flags(unsigned int flags)
46{
47 if ((flags & O_ACCMODE) == O_RDONLY)
48 return GENERIC_READ;
49 else if ((flags & O_ACCMODE) == O_WRONLY)
50 return GENERIC_WRITE;
51 else if ((flags & O_ACCMODE) == O_RDWR) {
52 /* GENERIC_ALL is too much permission to request
53 can cause unnecessary access denied on create */
54 /* return GENERIC_ALL; */
55 return (GENERIC_READ | GENERIC_WRITE);
56 }
57
Jeff Laytone10f7b52008-05-14 10:21:33 -070058 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
59 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
60 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000061}
Jeff Laytone10f7b52008-05-14 10:21:33 -070062
Jeff Layton608712f2010-10-15 15:33:56 -040063static u32 cifs_posix_convert_flags(unsigned int flags)
Steve French7fc8f4e2009-02-23 20:43:11 +000064{
Jeff Layton608712f2010-10-15 15:33:56 -040065 u32 posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070066
Steve French7fc8f4e2009-02-23 20:43:11 +000067 if ((flags & O_ACCMODE) == O_RDONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040068 posix_flags = SMB_O_RDONLY;
Steve French7fc8f4e2009-02-23 20:43:11 +000069 else if ((flags & O_ACCMODE) == O_WRONLY)
Jeff Layton608712f2010-10-15 15:33:56 -040070 posix_flags = SMB_O_WRONLY;
71 else if ((flags & O_ACCMODE) == O_RDWR)
72 posix_flags = SMB_O_RDWR;
73
74 if (flags & O_CREAT)
75 posix_flags |= SMB_O_CREAT;
76 if (flags & O_EXCL)
77 posix_flags |= SMB_O_EXCL;
78 if (flags & O_TRUNC)
79 posix_flags |= SMB_O_TRUNC;
80 /* be safe and imply O_SYNC for O_DSYNC */
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010081 if (flags & O_DSYNC)
Jeff Layton608712f2010-10-15 15:33:56 -040082 posix_flags |= SMB_O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000083 if (flags & O_DIRECTORY)
Jeff Layton608712f2010-10-15 15:33:56 -040084 posix_flags |= SMB_O_DIRECTORY;
Steve French7fc8f4e2009-02-23 20:43:11 +000085 if (flags & O_NOFOLLOW)
Jeff Layton608712f2010-10-15 15:33:56 -040086 posix_flags |= SMB_O_NOFOLLOW;
Steve French7fc8f4e2009-02-23 20:43:11 +000087 if (flags & O_DIRECT)
Jeff Layton608712f2010-10-15 15:33:56 -040088 posix_flags |= SMB_O_DIRECT;
Steve French7fc8f4e2009-02-23 20:43:11 +000089
90 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091}
92
93static inline int cifs_get_disposition(unsigned int flags)
94{
95 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
96 return FILE_CREATE;
97 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
98 return FILE_OVERWRITE_IF;
99 else if ((flags & O_CREAT) == O_CREAT)
100 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000101 else if ((flags & O_TRUNC) == O_TRUNC)
102 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 else
104 return FILE_OPEN;
105}
106
Jeff Laytondb460242010-06-16 13:40:17 -0400107static inline int cifs_open_inode_helper(struct inode *inode,
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530108 struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 char *full_path, int xid)
110{
Jeff Laytondb460242010-06-16 13:40:17 -0400111 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 struct timespec temp;
113 int rc;
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (pCifsInode->clientCanCacheRead) {
116 /* we have the inode open somewhere else
117 no need to discard cache data */
118 goto client_can_cache;
119 }
120
121 /* BB need same check in cifs_create too? */
122 /* if not oplocked, invalidate inode pages if mtime or file
123 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400124 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Jeff Laytondb460242010-06-16 13:40:17 -0400125 if (timespec_equal(&inode->i_mtime, &temp) &&
126 (inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000128 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 } else {
Jeff Laytondb460242010-06-16 13:40:17 -0400130 if (inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000131 /* BB no need to lock inode until after invalidate
132 since namei code should already have it locked? */
Jeff Laytondb460242010-06-16 13:40:17 -0400133 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400134 mapping_set_error(inode->i_mapping, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000136 cFYI(1, "invalidating remote inode since open detected it "
137 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400138 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140
141client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000142 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400143 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
144 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 else
Jeff Laytondb460242010-06-16 13:40:17 -0400146 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
147 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300149 cifs_set_oplock_level(inode, oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 return rc;
152}
153
Jeff Layton608712f2010-10-15 15:33:56 -0400154int cifs_posix_open(char *full_path, struct inode **pinode,
155 struct super_block *sb, int mode, unsigned int f_flags,
156 __u32 *poplock, __u16 *pnetfid, int xid)
157{
158 int rc;
159 FILE_UNIX_BASIC_INFO *presp_data;
160 __u32 posix_flags = 0;
161 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
162 struct cifs_fattr fattr;
163 struct tcon_link *tlink;
164 struct cifsTconInfo *tcon;
165
166 cFYI(1, "posix open %s", full_path);
167
168 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
169 if (presp_data == NULL)
170 return -ENOMEM;
171
172 tlink = cifs_sb_tlink(cifs_sb);
173 if (IS_ERR(tlink)) {
174 rc = PTR_ERR(tlink);
175 goto posix_open_ret;
176 }
177
178 tcon = tlink_tcon(tlink);
179 mode &= ~current_umask();
180
181 posix_flags = cifs_posix_convert_flags(f_flags);
182 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
183 poplock, full_path, cifs_sb->local_nls,
184 cifs_sb->mnt_cifs_flags &
185 CIFS_MOUNT_MAP_SPECIAL_CHR);
186 cifs_put_tlink(tlink);
187
188 if (rc)
189 goto posix_open_ret;
190
191 if (presp_data->Type == cpu_to_le32(-1))
192 goto posix_open_ret; /* open ok, caller does qpathinfo */
193
194 if (!pinode)
195 goto posix_open_ret; /* caller does not need info */
196
197 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
198
199 /* get new inode and set it up */
200 if (*pinode == NULL) {
201 cifs_fill_uniqueid(sb, &fattr);
202 *pinode = cifs_iget(sb, &fattr);
203 if (!*pinode) {
204 rc = -ENOMEM;
205 goto posix_open_ret;
206 }
207 } else {
208 cifs_fattr_to_inode(*pinode, &fattr);
209 }
210
211posix_open_ret:
212 kfree(presp_data);
213 return rc;
214}
215
Jeff Layton15ecb432010-10-15 15:34:02 -0400216struct cifsFileInfo *
217cifs_new_fileinfo(__u16 fileHandle, struct file *file,
218 struct tcon_link *tlink, __u32 oplock)
219{
220 struct dentry *dentry = file->f_path.dentry;
221 struct inode *inode = dentry->d_inode;
222 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
223 struct cifsFileInfo *pCifsFile;
224
225 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
226 if (pCifsFile == NULL)
227 return pCifsFile;
228
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400229 pCifsFile->count = 1;
Jeff Layton15ecb432010-10-15 15:34:02 -0400230 pCifsFile->netfid = fileHandle;
231 pCifsFile->pid = current->tgid;
232 pCifsFile->uid = current_fsuid();
233 pCifsFile->dentry = dget(dentry);
234 pCifsFile->f_flags = file->f_flags;
235 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400236 pCifsFile->tlink = cifs_get_tlink(tlink);
237 mutex_init(&pCifsFile->fh_mutex);
238 mutex_init(&pCifsFile->lock_mutex);
239 INIT_LIST_HEAD(&pCifsFile->llist);
Jeff Layton15ecb432010-10-15 15:34:02 -0400240 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
241
Jeff Layton44772882010-10-15 15:34:03 -0400242 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400243 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
244 /* if readable file instance put first in list*/
245 if (file->f_mode & FMODE_READ)
246 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
247 else
248 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400249 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400250
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300251 cifs_set_oplock_level(inode, oplock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400252
253 file->private_data = pCifsFile;
254 return pCifsFile;
255}
256
Steve Frenchcdff08e2010-10-21 22:46:14 +0000257/*
258 * Release a reference on the file private data. This may involve closing
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400259 * the filehandle out on the server. Must be called without holding
260 * cifs_file_list_lock.
Steve Frenchcdff08e2010-10-21 22:46:14 +0000261 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400262void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
263{
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300264 struct inode *inode = cifs_file->dentry->d_inode;
Steve Frenchcdff08e2010-10-21 22:46:14 +0000265 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300266 struct cifsInodeInfo *cifsi = CIFS_I(inode);
267 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000268 struct cifsLockInfo *li, *tmp;
269
270 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400271 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000272 spin_unlock(&cifs_file_list_lock);
273 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400274 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000275
276 /* remove it from the lists */
277 list_del(&cifs_file->flist);
278 list_del(&cifs_file->tlist);
279
280 if (list_empty(&cifsi->openFileList)) {
281 cFYI(1, "closing last open instance for inode %p",
282 cifs_file->dentry->d_inode);
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300283 cifs_set_oplock_level(inode, 0);
Steve Frenchcdff08e2010-10-21 22:46:14 +0000284 }
285 spin_unlock(&cifs_file_list_lock);
286
287 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
288 int xid, rc;
289
290 xid = GetXid();
291 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
292 FreeXid(xid);
293 }
294
295 /* Delete any outstanding lock records. We'll lose them when the file
296 * is closed anyway.
297 */
298 mutex_lock(&cifs_file->lock_mutex);
299 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
300 list_del(&li->llist);
301 kfree(li);
302 }
303 mutex_unlock(&cifs_file->lock_mutex);
304
305 cifs_put_tlink(cifs_file->tlink);
306 dput(cifs_file->dentry);
307 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400308}
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310int cifs_open(struct inode *inode, struct file *file)
311{
312 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400313 int xid;
314 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000316 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400317 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400318 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 char *full_path = NULL;
321 int desiredAccess;
322 int disposition;
323 __u16 netfid;
324 FILE_ALL_INFO *buf = NULL;
325
326 xid = GetXid();
327
328 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400329 tlink = cifs_sb_tlink(cifs_sb);
330 if (IS_ERR(tlink)) {
331 FreeXid(xid);
332 return PTR_ERR(tlink);
333 }
334 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Steve Frencha6ce4932009-04-09 01:14:32 +0000336 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800338 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530340 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400341 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 }
343
Joe Perchesb6b38f72010-04-21 03:50:45 +0000344 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
345 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000346
347 if (oplockEnabled)
348 oplock = REQ_OPLOCK;
349 else
350 oplock = 0;
351
Steve French64cc2c62009-03-04 19:54:08 +0000352 if (!tcon->broken_posix_open && tcon->unix_ext &&
353 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000354 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
355 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000356 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400357 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000358 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400359 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000360 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000361 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400362
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400363 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
364 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400365 if (pCifsFile == NULL) {
366 CIFSSMBClose(xid, tcon, netfid);
367 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400368 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530369
370 cifs_fscache_set_inode_cookie(inode, file);
371
Steve French276a74a2009-03-03 18:00:34 +0000372 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000373 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
374 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000375 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000376 " unexpected error on SMB posix open"
377 ", disabling posix open support."
378 " Check if server update available.",
379 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000380 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000381 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000382 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
383 (rc != -EOPNOTSUPP)) /* path not found or net err */
384 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000385 /* else fallthrough to retry open the old way on network i/o
386 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000387 }
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 desiredAccess = cifs_convert_flags(file->f_flags);
390
391/*********************************************************************
392 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000393 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000395 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 * O_CREAT FILE_OPEN_IF
397 * O_CREAT | O_EXCL FILE_CREATE
398 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
399 * O_TRUNC FILE_OVERWRITE
400 * none of the above FILE_OPEN
401 *
402 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000403 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 * O_CREAT | O_TRUNC is similar but truncates the existing
405 * file rather than creating a new file as FILE_SUPERSEDE does
406 * (which uses the attributes / metadata passed in on open call)
407 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000408 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 *? and the read write flags match reasonably. O_LARGEFILE
410 *? is irrelevant because largefile support is always used
411 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
412 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
413 *********************************************************************/
414
415 disposition = cifs_get_disposition(file->f_flags);
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 /* BB pass O_SYNC flag through on file attributes .. BB */
418
419 /* Also refresh inode by passing in file_info buf returned by SMBOpen
420 and calling get_inode_info with returned buf (at least helps
421 non-Unix server case) */
422
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000423 /* BB we can not do this if this is the second open of a file
424 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
426 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
427 if (!buf) {
428 rc = -ENOMEM;
429 goto out;
430 }
Steve French5bafd762006-06-07 00:18:43 +0000431
Jeff Laytona6e8a842010-09-20 16:01:33 -0700432 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000433 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000434 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700435 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
436 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000437 else
438 rc = -EIO; /* no NT SMB support fall into legacy open below */
439
Steve Frencha9d02ad2005-08-24 23:06:05 -0700440 if (rc == -EIO) {
441 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000442 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700443 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
444 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
445 & CIFS_MOUNT_MAP_SPECIAL_CHR);
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000448 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 goto out;
450 }
Jeff Layton3321b792009-09-25 09:53:37 -0400451
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530452 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400453 if (rc != 0)
454 goto out;
455
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400456 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400457 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 rc = -ENOMEM;
459 goto out;
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530462 cifs_fscache_set_inode_cookie(inode, file);
463
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 /* time to set mode which we can not set earlier due to
466 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000467 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400468 struct cifs_unix_set_info_args args = {
469 .mode = inode->i_mode,
470 .uid = NO_CHANGE_64,
471 .gid = NO_CHANGE_64,
472 .ctime = NO_CHANGE_64,
473 .atime = NO_CHANGE_64,
474 .mtime = NO_CHANGE_64,
475 .device = 0,
476 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400477 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
478 cifs_sb->local_nls,
479 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700480 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
482 }
483
484out:
485 kfree(buf);
486 kfree(full_path);
487 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400488 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 return rc;
490}
491
Adrian Bunk04187262006-06-30 18:23:04 +0200492/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493/* to server was lost */
494static int cifs_relock_file(struct cifsFileInfo *cifsFile)
495{
496 int rc = 0;
497
498/* BB list all locks open on this file and relock */
499
500 return rc;
501}
502
Jeff Layton15886172010-10-15 15:33:59 -0400503static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400506 int xid;
507 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000509 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 char *full_path = NULL;
513 int desiredAccess;
514 int disposition = FILE_OPEN;
515 __u16 netfid;
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400518 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000519 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400520 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530521 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530523 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
525
Jeff Layton15886172010-10-15 15:33:59 -0400526 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400528 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530/* can not grab rename sem here because various ops, including
531 those that already have the rename sem can end up causing writepage
532 to get called and if the server was down that means we end up here,
533 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400534 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000536 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400537 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000539 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
541
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400543 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 if (oplockEnabled)
546 oplock = REQ_OPLOCK;
547 else
Steve French4b18f2a2008-04-29 00:06:05 +0000548 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Steve French7fc8f4e2009-02-23 20:43:11 +0000550 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
551 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
552 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400553
554 /*
555 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
556 * original open. Must mask them off for a reopen.
557 */
Jeff Layton15886172010-10-15 15:33:59 -0400558 unsigned int oflags = pCifsFile->f_flags &
559 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400560
Jeff Layton2422f672010-06-16 13:40:16 -0400561 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000562 cifs_sb->mnt_file_mode /* ignored */,
563 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000564 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000565 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000566 goto reopen_success;
567 }
568 /* fallthrough to retry open the old way on errors, especially
569 in the reconnect path it is important to retry hard */
570 }
571
Jeff Layton15886172010-10-15 15:33:59 -0400572 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000575 by SMBOpen and then calling get_inode_info with returned buf
576 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 and server version of file size can be stale. If we knew for sure
578 that inode was not dirty locally we could do this */
579
Steve French7fc8f4e2009-02-23 20:43:11 +0000580 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000582 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700583 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400585 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000586 cFYI(1, "cifs_open returned 0x%x", rc);
587 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400588 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
Jeff Layton15886172010-10-15 15:33:59 -0400590
591reopen_success:
592 pCifsFile->netfid = netfid;
593 pCifsFile->invalidHandle = false;
594 mutex_unlock(&pCifsFile->fh_mutex);
595 pCifsInode = CIFS_I(inode);
596
597 if (can_flush) {
598 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -0400599 mapping_set_error(inode->i_mapping, rc);
Jeff Layton15886172010-10-15 15:33:59 -0400600
Jeff Layton15886172010-10-15 15:33:59 -0400601 if (tcon->unix_ext)
602 rc = cifs_get_inode_info_unix(&inode,
603 full_path, inode->i_sb, xid);
604 else
605 rc = cifs_get_inode_info(&inode,
606 full_path, NULL, inode->i_sb,
607 xid, NULL);
608 } /* else we are writing out data to server already
609 and could deadlock if we tried to flush data, and
610 since we do not know if we have data that would
611 invalidate the current end of file on the server
612 we can not go to the server to get the new inod
613 info */
Pavel Shilovskye66673e2010-11-02 12:00:42 +0300614
615 cifs_set_oplock_level(inode, oplock);
616
Jeff Layton15886172010-10-15 15:33:59 -0400617 cifs_relock_file(pCifsFile);
618
619reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 kfree(full_path);
621 FreeXid(xid);
622 return rc;
623}
624
625int cifs_close(struct inode *inode, struct file *file)
626{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000627 cifsFileInfo_put(file->private_data);
628 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Steve Frenchcdff08e2010-10-21 22:46:14 +0000630 /* return code from the ->release op is always ignored */
631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633
634int cifs_closedir(struct inode *inode, struct file *file)
635{
636 int rc = 0;
637 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700638 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 char *ptmp;
640
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 xid = GetXid();
644
645 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400646 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Joe Perchesb6b38f72010-04-21 03:50:45 +0000648 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400649 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000650 if (!pCFileStruct->srch_inf.endOfSearch &&
651 !pCFileStruct->invalidHandle) {
652 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400653 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000655 cFYI(1, "Closing uncompleted readdir with rc %d",
656 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* not much we can do if it fails anyway, ignore rc */
658 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000659 } else
Jeff Layton44772882010-10-15 15:34:03 -0400660 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
662 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000665 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000666 cifs_small_buf_release(ptmp);
667 else
668 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400670 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 kfree(file->private_data);
672 file->private_data = NULL;
673 }
674 /* BB can we lock the filestruct while this is going on? */
675 FreeXid(xid);
676 return rc;
677}
678
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000679static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
680 __u64 offset, __u8 lockType)
681{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000682 struct cifsLockInfo *li =
683 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000684 if (li == NULL)
685 return -ENOMEM;
686 li->offset = offset;
687 li->length = len;
688 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000689 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000690 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000691 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000692 return 0;
693}
694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
696{
697 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 __u32 numLock = 0;
699 __u32 numUnlock = 0;
700 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000701 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000703 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000704 __u16 netfid;
705 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000706 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 length = 1 + pfLock->fl_end - pfLock->fl_start;
709 rc = -EACCES;
710 xid = GetXid();
711
Joe Perchesb6b38f72010-04-21 03:50:45 +0000712 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000714 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000715 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000718 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000720 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000722 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000723 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000726 cFYI(1, "Process suspended by mandatory locking - "
727 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000729 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000730 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000732 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000735 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 numLock = 1;
737 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000738 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000740 /* Check if unlock includes more than
741 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000743 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 lockType |= LOCKING_ANDX_SHARED_LOCK;
745 numLock = 1;
746 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 numLock = 1;
749 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000750 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 lockType |= LOCKING_ANDX_SHARED_LOCK;
752 numLock = 1;
753 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800756 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400757 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
759 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530760 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530762 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
Steve French08547b02006-02-28 22:39:25 +0000764 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Steve French13a6e422008-12-02 17:24:33 +0000766 if ((tcon->ses->capabilities & CAP_UNIX) &&
767 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000768 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000769 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000770 /* BB add code here to normalize offset and length to
771 account for negative length which we can not accept over the
772 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000774 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000775 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000776 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000777 posix_lock_type = CIFS_RDLCK;
778 else
779 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000780 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000781 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000782 posix_lock_type, wait_flag);
783 FreeXid(xid);
784 return rc;
785 }
786
787 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000788 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000789 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000791 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 pfLock->fl_start, 1 /* numUnlock */ ,
793 0 /* numLock */ , lockType,
794 0 /* wait flag */ );
795 pfLock->fl_type = F_UNLCK;
796 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000797 cERROR(1, "Error unlocking previously locked "
798 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 rc = 0;
800
801 } else {
802 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400803 rc = 0;
804
805 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
806 pfLock->fl_type = F_WRLCK;
807 } else {
808 rc = CIFSSMBLock(xid, tcon, netfid, length,
809 pfLock->fl_start, 0, 1,
810 lockType | LOCKING_ANDX_SHARED_LOCK,
811 0 /* wait flag */);
812 if (rc == 0) {
813 rc = CIFSSMBLock(xid, tcon, netfid,
814 length, pfLock->fl_start, 1, 0,
815 lockType |
816 LOCKING_ANDX_SHARED_LOCK,
817 0 /* wait flag */);
818 pfLock->fl_type = F_RDLCK;
819 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000820 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400821 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000822 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400823 rc = 0;
824 } else {
825 pfLock->fl_type = F_WRLCK;
826 rc = 0;
827 }
828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
830
831 FreeXid(xid);
832 return rc;
833 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000834
835 if (!numLock && !numUnlock) {
836 /* if no lock or unlock then nothing
837 to do since we do not know what it is */
838 FreeXid(xid);
839 return -EOPNOTSUPP;
840 }
841
842 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000843 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000844 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000845 posix_lock_type = CIFS_RDLCK;
846 else
847 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000848
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000849 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000850 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000851
Steve French13a6e422008-12-02 17:24:33 +0000852 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000853 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000854 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000855 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700856 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857
858 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000859 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000860 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000861 0, numLock, lockType, wait_flag);
862
863 if (rc == 0) {
864 /* For Windows locks we must store them. */
865 rc = store_file_lock(fid, length,
866 pfLock->fl_start, lockType);
867 }
868 } else if (numUnlock) {
869 /* For each stored lock that this unlock overlaps
870 completely, unlock it. */
871 int stored_rc = 0;
872 struct cifsLockInfo *li, *tmp;
873
Steve French6b70c952006-09-21 07:35:29 +0000874 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000875 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000876 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
877 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000878 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000879 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000880 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000881 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000882 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000883 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000884 if (stored_rc)
885 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000886 else {
887 list_del(&li->llist);
888 kfree(li);
889 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890 }
891 }
Roland Dreier796e5662007-05-03 04:33:45 +0000892 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000893 }
894 }
895
Steve Frenchd634cc12005-08-26 14:42:59 -0500896 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 posix_lock_file_wait(file, pfLock);
898 FreeXid(xid);
899 return rc;
900}
901
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400902/*
903 * Set the timeout on write requests past EOF. For some servers (Windows)
904 * these calls can be very long.
905 *
906 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
907 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
908 * The 10M cutoff is totally arbitrary. A better scheme for this would be
909 * welcome if someone wants to suggest one.
910 *
911 * We may be able to do a better job with this if there were some way to
912 * declare that a file should be sparse.
913 */
914static int
915cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
916{
917 if (offset <= cifsi->server_eof)
918 return CIFS_STD_OP;
919 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
920 return CIFS_VLONG_OP;
921 else
922 return CIFS_LONG_OP;
923}
924
925/* update the file size (if needed) after a write */
926static void
927cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
928 unsigned int bytes_written)
929{
930 loff_t end_of_write = offset + bytes_written;
931
932 if (end_of_write > cifsi->server_eof)
933 cifsi->server_eof = end_of_write;
934}
935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936ssize_t cifs_user_write(struct file *file, const char __user *write_data,
937 size_t write_size, loff_t *poffset)
938{
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100939 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 int rc = 0;
941 unsigned int bytes_written = 0;
942 unsigned int total_written;
943 struct cifs_sb_info *cifs_sb;
944 struct cifsTconInfo *pTcon;
945 int xid, long_op;
946 struct cifsFileInfo *open_file;
Jiri Slaby50ae28f2010-11-01 16:08:55 +0100947 struct cifsInodeInfo *cifsi = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800949 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Joe Perchesb6b38f72010-04-21 03:50:45 +0000951 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
952 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 if (file->private_data == NULL)
955 return -EBADF;
Jeff Laytonba00ba642010-09-20 16:01:31 -0700956
Joe Perchesc21dfb62010-07-12 13:50:14 -0700957 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400958 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000959
Jeff Layton838726c2008-08-28 07:54:59 -0400960 rc = generic_write_checks(file, poffset, &write_size, 0);
961 if (rc)
962 return rc;
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400966 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 for (total_written = 0; write_size > total_written;
968 total_written += bytes_written) {
969 rc = -EAGAIN;
970 while (rc == -EAGAIN) {
971 if (file->private_data == NULL) {
972 /* file has been closed on us */
973 FreeXid(xid);
974 /* if we have gotten here we have written some data
975 and blocked, and the file has been freed on us while
976 we blocked so return what we managed to write */
977 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 /* we could deadlock if we called
981 filemap_fdatawait from here so tell
982 reopen_file not to flush data to server
983 now */
Jeff Layton15886172010-10-15 15:33:59 -0400984 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (rc != 0)
986 break;
987 }
988
989 rc = CIFSSMBWrite(xid, pTcon,
990 open_file->netfid,
991 min_t(const int, cifs_sb->wsize,
992 write_size - total_written),
993 *poffset, &bytes_written,
994 NULL, write_data + total_written, long_op);
995 }
996 if (rc || (bytes_written == 0)) {
997 if (total_written)
998 break;
999 else {
1000 FreeXid(xid);
1001 return rc;
1002 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001003 } else {
1004 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001006 }
Steve French133672e2007-11-13 22:41:37 +00001007 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 15 seconds is plenty */
1009 }
1010
Steve Frencha4544342005-08-24 13:59:35 -07001011 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001013/* Do not update local mtime - server will set its actual value on write
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001014 * inode->i_ctime = inode->i_mtime =
1015 * current_fs_time(inode->i_sb);*/
1016 if (total_written > 0) {
1017 spin_lock(&inode->i_lock);
1018 if (*poffset > inode->i_size)
1019 i_size_write(inode, *poffset);
1020 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
Jiri Slaby50ae28f2010-11-01 16:08:55 +01001022 mark_inode_dirty_sync(inode);
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 FreeXid(xid);
1025 return total_written;
1026}
1027
Jeff Layton7da4b492010-10-15 15:34:00 -04001028static ssize_t cifs_write(struct cifsFileInfo *open_file,
1029 const char *write_data, size_t write_size,
1030 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031{
1032 int rc = 0;
1033 unsigned int bytes_written = 0;
1034 unsigned int total_written;
1035 struct cifs_sb_info *cifs_sb;
1036 struct cifsTconInfo *pTcon;
1037 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001038 struct dentry *dentry = open_file->dentry;
1039 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Jeff Layton7da4b492010-10-15 15:34:00 -04001041 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Joe Perchesb6b38f72010-04-21 03:50:45 +00001043 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001044 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Jeff Layton13cfb732010-09-29 19:51:11 -04001046 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001050 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 for (total_written = 0; write_size > total_written;
1052 total_written += bytes_written) {
1053 rc = -EAGAIN;
1054 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* we could deadlock if we called
1057 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001058 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001060 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 if (rc != 0)
1062 break;
1063 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001064 if (experimEnabled || (pTcon->ses->server &&
1065 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001066 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001067 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001068 struct kvec iov[2];
1069 unsigned int len;
1070
Steve French0ae0efa2005-10-10 10:57:19 -07001071 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001072 write_size - total_written);
1073 /* iov[0] is reserved for smb header */
1074 iov[1].iov_base = (char *)write_data +
1075 total_written;
1076 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001077 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001078 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001079 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001080 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001081 } else
Steve French60808232006-04-22 15:53:05 +00001082 rc = CIFSSMBWrite(xid, pTcon,
1083 open_file->netfid,
1084 min_t(const int, cifs_sb->wsize,
1085 write_size - total_written),
1086 *poffset, &bytes_written,
1087 write_data + total_written,
1088 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090 if (rc || (bytes_written == 0)) {
1091 if (total_written)
1092 break;
1093 else {
1094 FreeXid(xid);
1095 return rc;
1096 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001097 } else {
1098 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001100 }
Steve French133672e2007-11-13 22:41:37 +00001101 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 15 seconds is plenty */
1103 }
1104
Steve Frencha4544342005-08-24 13:59:35 -07001105 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jeff Layton7da4b492010-10-15 15:34:00 -04001107 if (total_written > 0) {
1108 spin_lock(&dentry->d_inode->i_lock);
1109 if (*poffset > dentry->d_inode->i_size)
1110 i_size_write(dentry->d_inode, *poffset);
1111 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001113 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 FreeXid(xid);
1115 return total_written;
1116}
1117
Steve French630f3f0c2007-10-25 21:17:17 +00001118#ifdef CONFIG_CIFS_EXPERIMENTAL
Jeff Layton6508d902010-09-29 19:51:11 -04001119struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1120 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001121{
1122 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001123 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1124
1125 /* only filter by fsuid on multiuser mounts */
1126 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1127 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001128
Jeff Layton44772882010-10-15 15:34:03 -04001129 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001130 /* we could simply get the first_list_entry since write-only entries
1131 are always at the end of the list but since the first entry might
1132 have a close pending, we go through the whole list */
1133 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001134 if (fsuid_only && open_file->uid != current_fsuid())
1135 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001136 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001137 if (!open_file->invalidHandle) {
1138 /* found a good file */
1139 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001140 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001141 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001142 return open_file;
1143 } /* else might as well continue, and look for
1144 another, or simply have the caller reopen it
1145 again rather than trying to fix this handle */
1146 } else /* write only file */
1147 break; /* write only files are last so must be done */
1148 }
Jeff Layton44772882010-10-15 15:34:03 -04001149 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001150 return NULL;
1151}
1152#endif
1153
Jeff Layton6508d902010-09-29 19:51:11 -04001154struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1155 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001156{
1157 struct cifsFileInfo *open_file;
Jeff Layton6508d902010-09-29 19:51:11 -04001158 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
Jeff Layton2846d382008-09-22 21:33:33 -04001159 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001160 int rc;
Steve French6148a742005-10-05 12:23:19 -07001161
Steve French60808232006-04-22 15:53:05 +00001162 /* Having a null inode here (because mapping->host was set to zero by
1163 the VFS or MM) should not happen but we had reports of on oops (due to
1164 it being zero) during stress testcases so we need to check for it */
1165
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001166 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001167 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001168 dump_stack();
1169 return NULL;
1170 }
1171
Jeff Layton6508d902010-09-29 19:51:11 -04001172 /* only filter by fsuid on multiuser mounts */
1173 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1174 fsuid_only = false;
1175
Jeff Layton44772882010-10-15 15:34:03 -04001176 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001177refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001178 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001179 if (!any_available && open_file->pid != current->tgid)
1180 continue;
1181 if (fsuid_only && open_file->uid != current_fsuid())
1182 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001183 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001184 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001185
1186 if (!open_file->invalidHandle) {
1187 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001188 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001189 return open_file;
1190 }
Steve French8840dee2007-11-16 23:05:52 +00001191
Jeff Layton44772882010-10-15 15:34:03 -04001192 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001193
Steve French9b22b0b2007-10-02 01:11:08 +00001194 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001195 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001196 if (!rc)
1197 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001198
Steve Frenchcdff08e2010-10-21 22:46:14 +00001199 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001200 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001201 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001202
Steve Frenchcdff08e2010-10-21 22:46:14 +00001203 spin_lock(&cifs_file_list_lock);
1204
Steve French9b22b0b2007-10-02 01:11:08 +00001205 /* else we simply continue to the next entry. Thus
1206 we do not loop on reopen errors. If we
1207 can not reopen the file, for example if we
1208 reconnected to a server with another client
1209 racing to delete or lock the file we would not
1210 make progress if we restarted before the beginning
1211 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001212 }
1213 }
Jeff Layton2846d382008-09-22 21:33:33 -04001214 /* couldn't find useable FH with same pid, try any available */
1215 if (!any_available) {
1216 any_available = true;
1217 goto refind_writable;
1218 }
Jeff Layton44772882010-10-15 15:34:03 -04001219 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001220 return NULL;
1221}
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1224{
1225 struct address_space *mapping = page->mapping;
1226 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1227 char *write_data;
1228 int rc = -EFAULT;
1229 int bytes_written = 0;
1230 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001232 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 if (!mapping || !mapping->host)
1235 return -EFAULT;
1236
1237 inode = page->mapping->host;
1238 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 offset += (loff_t)from;
1241 write_data = kmap(page);
1242 write_data += from;
1243
1244 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1245 kunmap(page);
1246 return -EIO;
1247 }
1248
1249 /* racing with truncate? */
1250 if (offset > mapping->host->i_size) {
1251 kunmap(page);
1252 return 0; /* don't care */
1253 }
1254
1255 /* check to make sure that we are not extending the file */
1256 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001257 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Jeff Layton6508d902010-09-29 19:51:11 -04001259 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001260 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001261 bytes_written = cifs_write(open_file, write_data,
1262 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001263 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001265 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001266 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001267 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001268 else if (bytes_written < 0)
1269 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001270 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001271 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 rc = -EIO;
1273 }
1274
1275 kunmap(page);
1276 return rc;
1277}
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001280 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
Steve French37c0eb42005-10-05 14:50:29 -07001282 unsigned int bytes_to_write;
1283 unsigned int bytes_written;
1284 struct cifs_sb_info *cifs_sb;
1285 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001286 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001287 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001288 int range_whole = 0;
1289 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001290 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001291 int n_iov = 0;
1292 pgoff_t next;
1293 int nr_pages;
1294 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001295 struct cifsFileInfo *open_file;
Jeff Laytonba00ba642010-09-20 16:01:31 -07001296 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001297 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001298 struct page *page;
1299 struct pagevec pvec;
1300 int rc = 0;
1301 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001302 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Steve French37c0eb42005-10-05 14:50:29 -07001304 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001305
Steve French37c0eb42005-10-05 14:50:29 -07001306 /*
1307 * If wsize is smaller that the page cache size, default to writing
1308 * one page at a time via cifs_writepage
1309 */
1310 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1311 return generic_writepages(mapping, wbc);
1312
Steve French9a0c8232007-02-02 04:21:57 +00001313 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001314 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001315 return generic_writepages(mapping, wbc);
1316
Steve French37c0eb42005-10-05 14:50:29 -07001317 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001318 * if there's no open file, then this is likely to fail too,
1319 * but it'll at least handle the return. Maybe it should be
1320 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001321 */
Jeff Layton6508d902010-09-29 19:51:11 -04001322 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001323 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001324 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001325 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001326 }
1327
Jeff Layton13cfb732010-09-29 19:51:11 -04001328 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001329 if (!experimEnabled && tcon->ses->server->secMode &
1330 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1331 cifsFileInfo_put(open_file);
Dan Carpenter6b035902010-10-27 23:19:32 +02001332 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001333 return generic_writepages(mapping, wbc);
1334 }
1335 cifsFileInfo_put(open_file);
1336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 xid = GetXid();
1338
Steve French37c0eb42005-10-05 14:50:29 -07001339 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001340 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001341 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001342 end = -1;
1343 } else {
1344 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1345 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1346 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1347 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001348 scanned = 1;
1349 }
1350retry:
1351 while (!done && (index <= end) &&
1352 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1353 PAGECACHE_TAG_DIRTY,
1354 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1355 int first;
1356 unsigned int i;
1357
Steve French37c0eb42005-10-05 14:50:29 -07001358 first = -1;
1359 next = 0;
1360 n_iov = 0;
1361 bytes_to_write = 0;
1362
1363 for (i = 0; i < nr_pages; i++) {
1364 page = pvec.pages[i];
1365 /*
1366 * At this point we hold neither mapping->tree_lock nor
1367 * lock on the page itself: the page may be truncated or
1368 * invalidated (changing page->mapping to NULL), or even
1369 * swizzled back from swapper_space to tmpfs file
1370 * mapping
1371 */
1372
1373 if (first < 0)
1374 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001375 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001376 break;
1377
1378 if (unlikely(page->mapping != mapping)) {
1379 unlock_page(page);
1380 break;
1381 }
1382
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001383 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001384 done = 1;
1385 unlock_page(page);
1386 break;
1387 }
1388
1389 if (next && (page->index != next)) {
1390 /* Not next consecutive page */
1391 unlock_page(page);
1392 break;
1393 }
1394
1395 if (wbc->sync_mode != WB_SYNC_NONE)
1396 wait_on_page_writeback(page);
1397
1398 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001399 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001400 unlock_page(page);
1401 break;
1402 }
Steve French84d2f072005-10-12 15:32:05 -07001403
Linus Torvaldscb876f42006-12-23 16:19:07 -08001404 /*
1405 * This actually clears the dirty bit in the radix tree.
1406 * See cifs_writepage() for more commentary.
1407 */
1408 set_page_writeback(page);
1409
Steve French84d2f072005-10-12 15:32:05 -07001410 if (page_offset(page) >= mapping->host->i_size) {
1411 done = 1;
1412 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001413 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001414 break;
1415 }
1416
Steve French37c0eb42005-10-05 14:50:29 -07001417 /*
1418 * BB can we get rid of this? pages are held by pvec
1419 */
1420 page_cache_get(page);
1421
Steve French84d2f072005-10-12 15:32:05 -07001422 len = min(mapping->host->i_size - page_offset(page),
1423 (loff_t)PAGE_CACHE_SIZE);
1424
Steve French37c0eb42005-10-05 14:50:29 -07001425 /* reserve iov[0] for the smb header */
1426 n_iov++;
1427 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001428 iov[n_iov].iov_len = len;
1429 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001430
1431 if (first < 0) {
1432 first = i;
1433 offset = page_offset(page);
1434 }
1435 next = page->index + 1;
1436 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1437 break;
1438 }
1439 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001440 open_file = find_writable_file(CIFS_I(mapping->host),
1441 false);
Steve French23e7dd72005-10-20 13:44:56 -07001442 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001443 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001444 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001445 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001446 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001447 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001448 bytes_to_write, offset,
1449 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001450 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001451 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001452 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001453 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001454
1455 if (rc || bytes_written < bytes_to_write) {
1456 cERROR(1, "Write2 ret %d, wrote %d",
1457 rc, bytes_written);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001458 mapping_set_error(mapping, rc);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001459 } else {
1460 cifs_stats_bytes_written(tcon, bytes_written);
1461 }
1462
Steve French37c0eb42005-10-05 14:50:29 -07001463 for (i = 0; i < n_iov; i++) {
1464 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001465 /* Should we also set page error on
1466 success rc but too little data written? */
1467 /* BB investigate retry logic on temporary
1468 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001469 when page marked as error */
1470 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001471 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001472 kunmap(page);
1473 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001474 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001475 page_cache_release(page);
1476 }
1477 if ((wbc->nr_to_write -= n_iov) <= 0)
1478 done = 1;
1479 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001480 } else
1481 /* Need to re-find the pages we skipped */
1482 index = pvec.pages[0]->index + 1;
1483
Steve French37c0eb42005-10-05 14:50:29 -07001484 pagevec_release(&pvec);
1485 }
1486 if (!scanned && !done) {
1487 /*
1488 * We hit the last page and there is more work to be done: wrap
1489 * back to the start of the file
1490 */
1491 scanned = 1;
1492 index = 0;
1493 goto retry;
1494 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001495 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001496 mapping->writeback_index = index;
1497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001499 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 return rc;
1501}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001503static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504{
1505 int rc = -EFAULT;
1506 int xid;
1507
1508 xid = GetXid();
1509/* BB add check for wbc flags */
1510 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001511 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001512 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001513
1514 /*
1515 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1516 *
1517 * A writepage() implementation always needs to do either this,
1518 * or re-dirty the page with "redirty_page_for_writepage()" in
1519 * the case of a failure.
1520 *
1521 * Just unlocking the page will cause the radix tree tag-bits
1522 * to fail to update with the state of the page correctly.
1523 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001524 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1526 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1527 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001528 end_page_writeback(page);
1529 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 FreeXid(xid);
1531 return rc;
1532}
1533
Nick Piggind9414772008-09-24 11:32:59 -04001534static int cifs_write_end(struct file *file, struct address_space *mapping,
1535 loff_t pos, unsigned len, unsigned copied,
1536 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
Nick Piggind9414772008-09-24 11:32:59 -04001538 int rc;
1539 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Joe Perchesb6b38f72010-04-21 03:50:45 +00001541 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1542 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001543
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001544 if (PageChecked(page)) {
1545 if (copied == len)
1546 SetPageUptodate(page);
1547 ClearPageChecked(page);
1548 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001549 SetPageUptodate(page);
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001552 char *page_data;
1553 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1554 int xid;
1555
1556 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 /* this is probably better than directly calling
1558 partialpage_write since in this function the file handle is
1559 known which we might as well leverage */
1560 /* BB check if anything else missing out of ppw
1561 such as updating last write time */
1562 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001563 rc = cifs_write(file->private_data, page_data + offset,
1564 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001565 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001567
1568 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001569 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001570 rc = copied;
1571 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 set_page_dirty(page);
1573 }
1574
Nick Piggind9414772008-09-24 11:32:59 -04001575 if (rc > 0) {
1576 spin_lock(&inode->i_lock);
1577 if (pos > inode->i_size)
1578 i_size_write(inode, pos);
1579 spin_unlock(&inode->i_lock);
1580 }
1581
1582 unlock_page(page);
1583 page_cache_release(page);
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 return rc;
1586}
1587
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001588int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
1590 int xid;
1591 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001592 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001593 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001594 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 xid = GetXid();
1597
Joe Perchesb6b38f72010-04-21 03:50:45 +00001598 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001599 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001600
Jeff Laytoncea21802007-11-20 23:19:03 +00001601 rc = filemap_write_and_wait(inode->i_mapping);
1602 if (rc == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001603 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1604
Jeff Layton13cfb732010-09-29 19:51:11 -04001605 tcon = tlink_tcon(smbfile->tlink);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001606 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001607 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001608 }
Steve Frenchb298f222009-02-21 21:17:43 +00001609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 FreeXid(xid);
1611 return rc;
1612}
1613
NeilBrown3978d712006-03-26 01:37:17 -08001614/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 struct address_space *mapping;
1617 struct inode *inode;
1618 unsigned long index = page->index;
1619 unsigned int rpages = 0;
1620 int rc = 0;
1621
Steve Frenchf19159d2010-04-21 04:12:10 +00001622 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 mapping = page->mapping;
1624 if (!mapping)
1625 return 0;
1626 inode = mapping->host;
1627 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001628 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001630/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1632
Joe Perchesb6b38f72010-04-21 03:50:45 +00001633/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
NeilBrown3978d712006-03-26 01:37:17 -08001635#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (rc < 0)
1637 return rc;
1638 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001639#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640} */
1641
1642/*
1643 * As file closes, flush all cached write data for this inode checking
1644 * for write behind errors.
1645 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001646int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001648 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 int rc = 0;
1650
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001651 if (file->f_mode & FMODE_WRITE)
Jeff Laytond3f13222010-10-15 15:34:07 -04001652 rc = filemap_write_and_wait(inode->i_mapping);
Steve French50c2f752007-07-13 00:33:32 +00001653
Joe Perchesb6b38f72010-04-21 03:50:45 +00001654 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 return rc;
1657}
1658
1659ssize_t cifs_user_read(struct file *file, char __user *read_data,
1660 size_t read_size, loff_t *poffset)
1661{
1662 int rc = -EACCES;
1663 unsigned int bytes_read = 0;
1664 unsigned int total_read = 0;
1665 unsigned int current_read_size;
1666 struct cifs_sb_info *cifs_sb;
1667 struct cifsTconInfo *pTcon;
1668 int xid;
1669 struct cifsFileInfo *open_file;
1670 char *smb_read_data;
1671 char __user *current_offset;
1672 struct smb_com_read_rsp *pSMBr;
1673
1674 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001675 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
1677 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301678 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301680 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001682 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001683 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve Frenchad7a2922008-02-07 23:25:02 +00001685 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001686 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001687
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 for (total_read = 0, current_offset = read_data;
1689 read_size > total_read;
1690 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001691 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 cifs_sb->rsize);
1693 rc = -EAGAIN;
1694 smb_read_data = NULL;
1695 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001696 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001697 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001698 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (rc != 0)
1700 break;
1701 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001702 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001703 open_file->netfid,
1704 current_read_size, *poffset,
1705 &bytes_read, &smb_read_data,
1706 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001709 if (copy_to_user(current_offset,
1710 smb_read_data +
1711 4 /* RFC1001 length field */ +
1712 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001713 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001714 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001715
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001716 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001717 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001718 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001719 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 smb_read_data = NULL;
1721 }
1722 }
1723 if (rc || (bytes_read == 0)) {
1724 if (total_read) {
1725 break;
1726 } else {
1727 FreeXid(xid);
1728 return rc;
1729 }
1730 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001731 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 *poffset += bytes_read;
1733 }
1734 }
1735 FreeXid(xid);
1736 return total_read;
1737}
1738
1739
1740static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1741 loff_t *poffset)
1742{
1743 int rc = -EACCES;
1744 unsigned int bytes_read = 0;
1745 unsigned int total_read;
1746 unsigned int current_read_size;
1747 struct cifs_sb_info *cifs_sb;
1748 struct cifsTconInfo *pTcon;
1749 int xid;
1750 char *current_offset;
1751 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001752 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001755 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301758 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301760 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001762 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001763 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001766 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 read_size > total_read;
1770 total_read += bytes_read, current_offset += bytes_read) {
1771 current_read_size = min_t(const int, read_size - total_read,
1772 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001773 /* For windows me and 9x we do not want to request more
1774 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001776 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1777 current_read_size = min_t(const int, current_read_size,
1778 pTcon->ses->server->maxBuf - 128);
1779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 rc = -EAGAIN;
1781 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001782 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001783 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 if (rc != 0)
1785 break;
1786 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001787 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001788 open_file->netfid,
1789 current_read_size, *poffset,
1790 &bytes_read, &current_offset,
1791 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 }
1793 if (rc || (bytes_read == 0)) {
1794 if (total_read) {
1795 break;
1796 } else {
1797 FreeXid(xid);
1798 return rc;
1799 }
1800 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001801 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 *poffset += bytes_read;
1803 }
1804 }
1805 FreeXid(xid);
1806 return total_read;
1807}
1808
1809int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1810{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 int rc, xid;
1812
1813 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001814 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001816 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 FreeXid(xid);
1818 return rc;
1819 }
1820 rc = generic_file_mmap(file, vma);
1821 FreeXid(xid);
1822 return rc;
1823}
1824
1825
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001826static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001827 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
1829 struct page *page;
1830 char *target;
1831
1832 while (bytes_read > 0) {
1833 if (list_empty(pages))
1834 break;
1835
1836 page = list_entry(pages->prev, struct page, lru);
1837 list_del(&page->lru);
1838
Nick Piggin315e9952010-04-21 03:18:28 +00001839 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 GFP_KERNEL)) {
1841 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001842 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001843 data += PAGE_CACHE_SIZE;
1844 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 continue;
1846 }
Jeff Layton06b43672010-06-01 10:54:45 -04001847 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001849 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 if (PAGE_CACHE_SIZE > bytes_read) {
1852 memcpy(target, data, bytes_read);
1853 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001854 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 PAGE_CACHE_SIZE - bytes_read);
1856 bytes_read = 0;
1857 } else {
1858 memcpy(target, data, PAGE_CACHE_SIZE);
1859 bytes_read -= PAGE_CACHE_SIZE;
1860 }
1861 kunmap_atomic(target, KM_USER0);
1862
1863 flush_dcache_page(page);
1864 SetPageUptodate(page);
1865 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301867
1868 /* add page to FS-Cache */
1869 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 }
1871 return;
1872}
1873
1874static int cifs_readpages(struct file *file, struct address_space *mapping,
1875 struct list_head *page_list, unsigned num_pages)
1876{
1877 int rc = -EACCES;
1878 int xid;
1879 loff_t offset;
1880 struct page *page;
1881 struct cifs_sb_info *cifs_sb;
1882 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001883 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001884 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 char *smb_read_data = NULL;
1886 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001888 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 xid = GetXid();
1891 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301892 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301894 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001896 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001897 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001898 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001899
Suresh Jayaraman566982362010-07-05 18:13:25 +05301900 /*
1901 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1902 * immediately if the cookie is negative
1903 */
1904 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1905 &num_pages);
1906 if (rc == 0)
1907 goto read_complete;
1908
Steve Frenchf19159d2010-04-21 04:12:10 +00001909 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 for (i = 0; i < num_pages; ) {
1911 unsigned contig_pages;
1912 struct page *tmp_page;
1913 unsigned long expected_index;
1914
1915 if (list_empty(page_list))
1916 break;
1917
1918 page = list_entry(page_list->prev, struct page, lru);
1919 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1920
1921 /* count adjacent pages that we will read into */
1922 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001923 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001925 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 if (tmp_page->index == expected_index) {
1927 contig_pages++;
1928 expected_index++;
1929 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001930 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 }
1932 if (contig_pages + i > num_pages)
1933 contig_pages = num_pages - i;
1934
1935 /* for reads over a certain size could initiate async
1936 read ahead */
1937
1938 read_size = contig_pages * PAGE_CACHE_SIZE;
1939 /* Read size needs to be in multiples of one page */
1940 read_size = min_t(const unsigned int, read_size,
1941 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001942 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1943 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 rc = -EAGAIN;
1945 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001946 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001947 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 if (rc != 0)
1949 break;
1950 }
1951
Steve Frenchbfa0d752005-08-31 21:50:37 -07001952 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001953 open_file->netfid,
1954 read_size, offset,
1955 &bytes_read, &smb_read_data,
1956 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001957 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001958 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001960 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001961 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001962 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001963 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 smb_read_data = NULL;
1965 }
1966 }
1967 }
1968 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001969 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 break;
1971 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08001972 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1974 cifs_copy_cache_pages(mapping, page_list, bytes_read,
1975 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00001976 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
1978 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07001979 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00001980 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 i++; /* account for partial page */
1982
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001983 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001985 /* BB do we need to verify this common case ?
1986 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 we will hit it on next read */
1988
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08001989 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 }
1991 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001992 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00001993 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001994 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001995 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 break;
1998 }
1999 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002000 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002001 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002002 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002003 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 smb_read_data = NULL;
2005 }
2006 bytes_read = 0;
2007 }
2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009/* need to free smb_read_data buf before exit */
2010 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002011 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002012 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002013 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002014 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Suresh Jayaraman566982362010-07-05 18:13:25 +05302018read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 FreeXid(xid);
2020 return rc;
2021}
2022
2023static int cifs_readpage_worker(struct file *file, struct page *page,
2024 loff_t *poffset)
2025{
2026 char *read_data;
2027 int rc;
2028
Suresh Jayaraman566982362010-07-05 18:13:25 +05302029 /* Is the page cached? */
2030 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2031 if (rc == 0)
2032 goto read_complete;
2033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 page_cache_get(page);
2035 read_data = kmap(page);
2036 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if (rc < 0)
2041 goto io_error;
2042 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002043 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002044
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002045 file->f_path.dentry->d_inode->i_atime =
2046 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 if (PAGE_CACHE_SIZE > rc)
2049 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2050
2051 flush_dcache_page(page);
2052 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302053
2054 /* send this page to the cache */
2055 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002058
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002060 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 page_cache_release(page);
Suresh Jayaraman566982362010-07-05 18:13:25 +05302062
2063read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 return rc;
2065}
2066
2067static int cifs_readpage(struct file *file, struct page *page)
2068{
2069 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2070 int rc = -EACCES;
2071 int xid;
2072
2073 xid = GetXid();
2074
2075 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302076 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302078 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 }
2080
Joe Perchesb6b38f72010-04-21 03:50:45 +00002081 cFYI(1, "readpage %p at offset %d 0x%x\n",
2082 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 rc = cifs_readpage_worker(file, page, &offset);
2085
2086 unlock_page(page);
2087
2088 FreeXid(xid);
2089 return rc;
2090}
2091
Steve Frencha403a0a2007-07-26 15:54:16 +00002092static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2093{
2094 struct cifsFileInfo *open_file;
2095
Jeff Layton44772882010-10-15 15:34:03 -04002096 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002097 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002098 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002099 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002100 return 1;
2101 }
2102 }
Jeff Layton44772882010-10-15 15:34:03 -04002103 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002104 return 0;
2105}
2106
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107/* We do not want to update the file size from server for inodes
2108 open for write - to avoid races with writepage extending
2109 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 but this is tricky to do without racing with writebehind
2112 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002113bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114{
Steve Frencha403a0a2007-07-26 15:54:16 +00002115 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002116 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002117
Steve Frencha403a0a2007-07-26 15:54:16 +00002118 if (is_inode_writable(cifsInode)) {
2119 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002120 struct cifs_sb_info *cifs_sb;
2121
Steve Frenchc32a0b62006-01-12 14:41:28 -08002122 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002123 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002124 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002125 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002126 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002127 }
2128
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002129 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002130 return true;
Steve French7ba526312007-02-08 18:14:13 +00002131
Steve French4b18f2a2008-04-29 00:06:05 +00002132 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002133 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002134 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135}
2136
Nick Piggind9414772008-09-24 11:32:59 -04002137static int cifs_write_begin(struct file *file, struct address_space *mapping,
2138 loff_t pos, unsigned len, unsigned flags,
2139 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140{
Nick Piggind9414772008-09-24 11:32:59 -04002141 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2142 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002143 loff_t page_start = pos & PAGE_MASK;
2144 loff_t i_size;
2145 struct page *page;
2146 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
Joe Perchesb6b38f72010-04-21 03:50:45 +00002148 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002149
Nick Piggin54566b22009-01-04 12:00:53 -08002150 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002151 if (!page) {
2152 rc = -ENOMEM;
2153 goto out;
2154 }
Nick Piggind9414772008-09-24 11:32:59 -04002155
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002156 if (PageUptodate(page))
2157 goto out;
Steve French8a236262007-03-06 00:31:00 +00002158
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002159 /*
2160 * If we write a full page it will be up to date, no need to read from
2161 * the server. If the write is short, we'll end up doing a sync write
2162 * instead.
2163 */
2164 if (len == PAGE_CACHE_SIZE)
2165 goto out;
2166
2167 /*
2168 * optimize away the read when we have an oplock, and we're not
2169 * expecting to use any of the data we'd be reading in. That
2170 * is, when the page lies beyond the EOF, or straddles the EOF
2171 * and the write will cover all of the existing data.
2172 */
2173 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2174 i_size = i_size_read(mapping->host);
2175 if (page_start >= i_size ||
2176 (offset == 0 && (pos + len) >= i_size)) {
2177 zero_user_segments(page, 0, offset,
2178 offset + len,
2179 PAGE_CACHE_SIZE);
2180 /*
2181 * PageChecked means that the parts of the page
2182 * to which we're not writing are considered up
2183 * to date. Once the data is copied to the
2184 * page, it can be set uptodate.
2185 */
2186 SetPageChecked(page);
2187 goto out;
2188 }
2189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
Nick Piggind9414772008-09-24 11:32:59 -04002191 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002192 /*
2193 * might as well read a page, it is fast enough. If we get
2194 * an error, we don't need to return it. cifs_write_end will
2195 * do a sync write instead since PG_uptodate isn't set.
2196 */
2197 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002198 } else {
2199 /* we could try using another file handle if there is one -
2200 but how would we lock it to prevent close of that handle
2201 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002202 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002203 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002204out:
2205 *pagep = page;
2206 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207}
2208
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302209static int cifs_release_page(struct page *page, gfp_t gfp)
2210{
2211 if (PagePrivate(page))
2212 return 0;
2213
2214 return cifs_fscache_release_page(page, gfp);
2215}
2216
2217static void cifs_invalidate_page(struct page *page, unsigned long offset)
2218{
2219 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2220
2221 if (offset == 0)
2222 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2223}
2224
Tejun Heo9b646972010-07-20 22:09:02 +02002225void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002226{
2227 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2228 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002229 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002230 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002231 int rc = 0;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002232
2233 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002234 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002235 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002236 else
Al Viro8737c932009-12-24 06:47:55 -05002237 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002238 rc = filemap_fdatawrite(inode->i_mapping);
2239 if (cinode->clientCanCacheRead == 0) {
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002240 rc = filemap_fdatawait(inode->i_mapping);
2241 mapping_set_error(inode->i_mapping, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002242 invalidate_remote_inode(inode);
2243 }
Joe Perchesb6b38f72010-04-21 03:50:45 +00002244 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002245 }
2246
2247 /*
2248 * releasing stale oplock after recent reconnect of smb session using
2249 * a now incorrect file handle is not a data integrity issue but do
2250 * not bother sending an oplock release if session to server still is
2251 * disconnected since oplock already released by the server
2252 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002253 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002254 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2255 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002256 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002257 }
Tejun Heo9b646972010-07-20 22:09:02 +02002258
2259 /*
2260 * We might have kicked in before is_valid_oplock_break()
2261 * finished grabbing reference for us. Make sure it's done by
Suresh Jayaraman6573e9b2010-10-18 23:52:18 +05302262 * waiting for cifs_file_list_lock.
Tejun Heo9b646972010-07-20 22:09:02 +02002263 */
Jeff Layton44772882010-10-15 15:34:03 -04002264 spin_lock(&cifs_file_list_lock);
2265 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002266
2267 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002268}
2269
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002270/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002271void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002272{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002273 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002274 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002275}
2276
Tejun Heo9b646972010-07-20 22:09:02 +02002277void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002278{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002279 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002280 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002281}
2282
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002283const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 .readpage = cifs_readpage,
2285 .readpages = cifs_readpages,
2286 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002287 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002288 .write_begin = cifs_write_begin,
2289 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302291 .releasepage = cifs_release_page,
2292 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 /* .sync_page = cifs_sync_page, */
2294 /* .direct_IO = */
2295};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002296
2297/*
2298 * cifs_readpages requires the server to support a buffer large enough to
2299 * contain the header plus one complete page of data. Otherwise, we need
2300 * to leave cifs_readpages out of the address space operations.
2301 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002302const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002303 .readpage = cifs_readpage,
2304 .writepage = cifs_writepage,
2305 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002306 .write_begin = cifs_write_begin,
2307 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002308 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302309 .releasepage = cifs_release_page,
2310 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002311 /* .sync_page = cifs_sync_page, */
2312 /* .direct_IO = */
2313};