blob: baf4b5067ff94bd46ebdea43aed81314cda3d1db [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 Laytoncea21802007-11-20 23:19:03 +0000134 if (rc != 0)
Jeff Laytondb460242010-06-16 13:40:17 -0400135 pCifsInode->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000137 cFYI(1, "invalidating remote inode since open detected it "
138 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400139 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 }
141
142client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000143 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400144 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
145 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 else
Jeff Laytondb460242010-06-16 13:40:17 -0400147 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
148 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530150 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000151 pCifsInode->clientCanCacheAll = true;
152 pCifsInode->clientCanCacheRead = true;
Jeff Laytondb460242010-06-16 13:40:17 -0400153 cFYI(1, "Exclusive Oplock granted on inode %p", inode);
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530154 } else if ((oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000155 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 return rc;
158}
159
Jeff Layton608712f2010-10-15 15:33:56 -0400160int cifs_posix_open(char *full_path, struct inode **pinode,
161 struct super_block *sb, int mode, unsigned int f_flags,
162 __u32 *poplock, __u16 *pnetfid, int xid)
163{
164 int rc;
165 FILE_UNIX_BASIC_INFO *presp_data;
166 __u32 posix_flags = 0;
167 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
168 struct cifs_fattr fattr;
169 struct tcon_link *tlink;
170 struct cifsTconInfo *tcon;
171
172 cFYI(1, "posix open %s", full_path);
173
174 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
175 if (presp_data == NULL)
176 return -ENOMEM;
177
178 tlink = cifs_sb_tlink(cifs_sb);
179 if (IS_ERR(tlink)) {
180 rc = PTR_ERR(tlink);
181 goto posix_open_ret;
182 }
183
184 tcon = tlink_tcon(tlink);
185 mode &= ~current_umask();
186
187 posix_flags = cifs_posix_convert_flags(f_flags);
188 rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
189 poplock, full_path, cifs_sb->local_nls,
190 cifs_sb->mnt_cifs_flags &
191 CIFS_MOUNT_MAP_SPECIAL_CHR);
192 cifs_put_tlink(tlink);
193
194 if (rc)
195 goto posix_open_ret;
196
197 if (presp_data->Type == cpu_to_le32(-1))
198 goto posix_open_ret; /* open ok, caller does qpathinfo */
199
200 if (!pinode)
201 goto posix_open_ret; /* caller does not need info */
202
203 cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
204
205 /* get new inode and set it up */
206 if (*pinode == NULL) {
207 cifs_fill_uniqueid(sb, &fattr);
208 *pinode = cifs_iget(sb, &fattr);
209 if (!*pinode) {
210 rc = -ENOMEM;
211 goto posix_open_ret;
212 }
213 } else {
214 cifs_fattr_to_inode(*pinode, &fattr);
215 }
216
217posix_open_ret:
218 kfree(presp_data);
219 return rc;
220}
221
Jeff Layton15ecb432010-10-15 15:34:02 -0400222struct cifsFileInfo *
223cifs_new_fileinfo(__u16 fileHandle, struct file *file,
224 struct tcon_link *tlink, __u32 oplock)
225{
226 struct dentry *dentry = file->f_path.dentry;
227 struct inode *inode = dentry->d_inode;
228 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
229 struct cifsFileInfo *pCifsFile;
230
231 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
232 if (pCifsFile == NULL)
233 return pCifsFile;
234
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400235 pCifsFile->count = 1;
Jeff Layton15ecb432010-10-15 15:34:02 -0400236 pCifsFile->netfid = fileHandle;
237 pCifsFile->pid = current->tgid;
238 pCifsFile->uid = current_fsuid();
239 pCifsFile->dentry = dget(dentry);
240 pCifsFile->f_flags = file->f_flags;
241 pCifsFile->invalidHandle = false;
Jeff Layton15ecb432010-10-15 15:34:02 -0400242 pCifsFile->tlink = cifs_get_tlink(tlink);
243 mutex_init(&pCifsFile->fh_mutex);
244 mutex_init(&pCifsFile->lock_mutex);
245 INIT_LIST_HEAD(&pCifsFile->llist);
Jeff Layton15ecb432010-10-15 15:34:02 -0400246 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
247
Jeff Layton44772882010-10-15 15:34:03 -0400248 spin_lock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400249 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
250 /* if readable file instance put first in list*/
251 if (file->f_mode & FMODE_READ)
252 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
253 else
254 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
Jeff Layton44772882010-10-15 15:34:03 -0400255 spin_unlock(&cifs_file_list_lock);
Jeff Layton15ecb432010-10-15 15:34:02 -0400256
257 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
258 pCifsInode->clientCanCacheAll = true;
259 pCifsInode->clientCanCacheRead = true;
260 cFYI(1, "Exclusive Oplock inode %p", inode);
261 } else if ((oplock & 0xF) == OPLOCK_READ)
262 pCifsInode->clientCanCacheRead = true;
263
264 file->private_data = pCifsFile;
265 return pCifsFile;
266}
267
Steve Frenchcdff08e2010-10-21 22:46:14 +0000268/*
269 * Release a reference on the file private data. This may involve closing
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400270 * the filehandle out on the server. Must be called without holding
271 * cifs_file_list_lock.
Steve Frenchcdff08e2010-10-21 22:46:14 +0000272 */
Jeff Laytonb33879a2010-10-15 15:34:04 -0400273void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
274{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000275 struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
276 struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
277 struct cifsLockInfo *li, *tmp;
278
279 spin_lock(&cifs_file_list_lock);
Jeff Layton5f6dbc92010-10-15 15:34:06 -0400280 if (--cifs_file->count > 0) {
Steve Frenchcdff08e2010-10-21 22:46:14 +0000281 spin_unlock(&cifs_file_list_lock);
282 return;
Jeff Laytonb33879a2010-10-15 15:34:04 -0400283 }
Steve Frenchcdff08e2010-10-21 22:46:14 +0000284
285 /* remove it from the lists */
286 list_del(&cifs_file->flist);
287 list_del(&cifs_file->tlist);
288
289 if (list_empty(&cifsi->openFileList)) {
290 cFYI(1, "closing last open instance for inode %p",
291 cifs_file->dentry->d_inode);
292 cifsi->clientCanCacheRead = false;
293 cifsi->clientCanCacheAll = false;
294 }
295 spin_unlock(&cifs_file_list_lock);
296
297 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
298 int xid, rc;
299
300 xid = GetXid();
301 rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
302 FreeXid(xid);
303 }
304
305 /* Delete any outstanding lock records. We'll lose them when the file
306 * is closed anyway.
307 */
308 mutex_lock(&cifs_file->lock_mutex);
309 list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
310 list_del(&li->llist);
311 kfree(li);
312 }
313 mutex_unlock(&cifs_file->lock_mutex);
314
315 cifs_put_tlink(cifs_file->tlink);
316 dput(cifs_file->dentry);
317 kfree(cifs_file);
Jeff Laytonb33879a2010-10-15 15:34:04 -0400318}
319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320int cifs_open(struct inode *inode, struct file *file)
321{
322 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400323 int xid;
324 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000326 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400327 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400328 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 char *full_path = NULL;
331 int desiredAccess;
332 int disposition;
333 __u16 netfid;
334 FILE_ALL_INFO *buf = NULL;
335
336 xid = GetXid();
337
338 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400339 tlink = cifs_sb_tlink(cifs_sb);
340 if (IS_ERR(tlink)) {
341 FreeXid(xid);
342 return PTR_ERR(tlink);
343 }
344 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Steve Frencha6ce4932009-04-09 01:14:32 +0000346 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800348 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530350 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400351 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 }
353
Joe Perchesb6b38f72010-04-21 03:50:45 +0000354 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
355 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000356
357 if (oplockEnabled)
358 oplock = REQ_OPLOCK;
359 else
360 oplock = 0;
361
Steve French64cc2c62009-03-04 19:54:08 +0000362 if (!tcon->broken_posix_open && tcon->unix_ext &&
363 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000364 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
365 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000366 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400367 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000368 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400369 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000370 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000371 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400372
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400373 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
374 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400375 if (pCifsFile == NULL) {
376 CIFSSMBClose(xid, tcon, netfid);
377 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400378 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530379
380 cifs_fscache_set_inode_cookie(inode, file);
381
Steve French276a74a2009-03-03 18:00:34 +0000382 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000383 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
384 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000385 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000386 " unexpected error on SMB posix open"
387 ", disabling posix open support."
388 " Check if server update available.",
389 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000390 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000391 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000392 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
393 (rc != -EOPNOTSUPP)) /* path not found or net err */
394 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000395 /* else fallthrough to retry open the old way on network i/o
396 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000397 }
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 desiredAccess = cifs_convert_flags(file->f_flags);
400
401/*********************************************************************
402 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000403 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000405 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 * O_CREAT FILE_OPEN_IF
407 * O_CREAT | O_EXCL FILE_CREATE
408 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
409 * O_TRUNC FILE_OVERWRITE
410 * none of the above FILE_OPEN
411 *
412 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000413 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 * O_CREAT | O_TRUNC is similar but truncates the existing
415 * file rather than creating a new file as FILE_SUPERSEDE does
416 * (which uses the attributes / metadata passed in on open call)
417 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000418 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 *? and the read write flags match reasonably. O_LARGEFILE
420 *? is irrelevant because largefile support is always used
421 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
422 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
423 *********************************************************************/
424
425 disposition = cifs_get_disposition(file->f_flags);
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 /* BB pass O_SYNC flag through on file attributes .. BB */
428
429 /* Also refresh inode by passing in file_info buf returned by SMBOpen
430 and calling get_inode_info with returned buf (at least helps
431 non-Unix server case) */
432
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000433 /* BB we can not do this if this is the second open of a file
434 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
436 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
437 if (!buf) {
438 rc = -ENOMEM;
439 goto out;
440 }
Steve French5bafd762006-06-07 00:18:43 +0000441
Jeff Laytona6e8a842010-09-20 16:01:33 -0700442 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000443 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000444 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700445 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
446 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000447 else
448 rc = -EIO; /* no NT SMB support fall into legacy open below */
449
Steve Frencha9d02ad2005-08-24 23:06:05 -0700450 if (rc == -EIO) {
451 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000452 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700453 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
454 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
455 & CIFS_MOUNT_MAP_SPECIAL_CHR);
456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000458 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 goto out;
460 }
Jeff Layton3321b792009-09-25 09:53:37 -0400461
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530462 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400463 if (rc != 0)
464 goto out;
465
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400466 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400467 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 rc = -ENOMEM;
469 goto out;
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530472 cifs_fscache_set_inode_cookie(inode, file);
473
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /* time to set mode which we can not set earlier due to
476 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000477 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400478 struct cifs_unix_set_info_args args = {
479 .mode = inode->i_mode,
480 .uid = NO_CHANGE_64,
481 .gid = NO_CHANGE_64,
482 .ctime = NO_CHANGE_64,
483 .atime = NO_CHANGE_64,
484 .mtime = NO_CHANGE_64,
485 .device = 0,
486 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400487 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
488 cifs_sb->local_nls,
489 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700490 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 }
492 }
493
494out:
495 kfree(buf);
496 kfree(full_path);
497 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400498 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return rc;
500}
501
Adrian Bunk04187262006-06-30 18:23:04 +0200502/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/* to server was lost */
504static int cifs_relock_file(struct cifsFileInfo *cifsFile)
505{
506 int rc = 0;
507
508/* BB list all locks open on this file and relock */
509
510 return rc;
511}
512
Jeff Layton15886172010-10-15 15:33:59 -0400513static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400516 int xid;
517 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000519 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000521 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 char *full_path = NULL;
523 int desiredAccess;
524 int disposition = FILE_OPEN;
525 __u16 netfid;
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400528 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000529 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400530 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530531 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530533 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
535
Jeff Layton15886172010-10-15 15:33:59 -0400536 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400538 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540/* can not grab rename sem here because various ops, including
541 those that already have the rename sem can end up causing writepage
542 to get called and if the server was down that means we end up here,
543 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400544 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000546 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400547 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000549 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
551
Joe Perchesb6b38f72010-04-21 03:50:45 +0000552 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400553 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (oplockEnabled)
556 oplock = REQ_OPLOCK;
557 else
Steve French4b18f2a2008-04-29 00:06:05 +0000558 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Steve French7fc8f4e2009-02-23 20:43:11 +0000560 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
561 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
562 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400563
564 /*
565 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
566 * original open. Must mask them off for a reopen.
567 */
Jeff Layton15886172010-10-15 15:33:59 -0400568 unsigned int oflags = pCifsFile->f_flags &
569 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400570
Jeff Layton2422f672010-06-16 13:40:16 -0400571 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000572 cifs_sb->mnt_file_mode /* ignored */,
573 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000574 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000575 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000576 goto reopen_success;
577 }
578 /* fallthrough to retry open the old way on errors, especially
579 in the reconnect path it is important to retry hard */
580 }
581
Jeff Layton15886172010-10-15 15:33:59 -0400582 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000585 by SMBOpen and then calling get_inode_info with returned buf
586 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 and server version of file size can be stale. If we knew for sure
588 that inode was not dirty locally we could do this */
589
Steve French7fc8f4e2009-02-23 20:43:11 +0000590 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000592 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700593 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400595 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cFYI(1, "cifs_open returned 0x%x", rc);
597 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400598 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
Jeff Layton15886172010-10-15 15:33:59 -0400600
601reopen_success:
602 pCifsFile->netfid = netfid;
603 pCifsFile->invalidHandle = false;
604 mutex_unlock(&pCifsFile->fh_mutex);
605 pCifsInode = CIFS_I(inode);
606
607 if (can_flush) {
608 rc = filemap_write_and_wait(inode->i_mapping);
609 if (rc != 0)
610 CIFS_I(inode)->write_behind_rc = rc;
611
612 pCifsInode->clientCanCacheAll = false;
613 pCifsInode->clientCanCacheRead = false;
614 if (tcon->unix_ext)
615 rc = cifs_get_inode_info_unix(&inode,
616 full_path, inode->i_sb, xid);
617 else
618 rc = cifs_get_inode_info(&inode,
619 full_path, NULL, inode->i_sb,
620 xid, NULL);
621 } /* else we are writing out data to server already
622 and could deadlock if we tried to flush data, and
623 since we do not know if we have data that would
624 invalidate the current end of file on the server
625 we can not go to the server to get the new inod
626 info */
627 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
628 pCifsInode->clientCanCacheAll = true;
629 pCifsInode->clientCanCacheRead = true;
630 cFYI(1, "Exclusive Oplock granted on inode %p",
631 pCifsFile->dentry->d_inode);
632 } else if ((oplock & 0xF) == OPLOCK_READ) {
633 pCifsInode->clientCanCacheRead = true;
634 pCifsInode->clientCanCacheAll = false;
635 } else {
636 pCifsInode->clientCanCacheRead = false;
637 pCifsInode->clientCanCacheAll = false;
638 }
639 cifs_relock_file(pCifsFile);
640
641reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 kfree(full_path);
643 FreeXid(xid);
644 return rc;
645}
646
647int cifs_close(struct inode *inode, struct file *file)
648{
Steve Frenchcdff08e2010-10-21 22:46:14 +0000649 cifsFileInfo_put(file->private_data);
650 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Steve Frenchcdff08e2010-10-21 22:46:14 +0000652 /* return code from the ->release op is always ignored */
653 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
656int cifs_closedir(struct inode *inode, struct file *file)
657{
658 int rc = 0;
659 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700660 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 char *ptmp;
662
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 xid = GetXid();
666
667 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400668 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Joe Perchesb6b38f72010-04-21 03:50:45 +0000670 cFYI(1, "Freeing private data in close dir");
Jeff Layton44772882010-10-15 15:34:03 -0400671 spin_lock(&cifs_file_list_lock);
Steve French4b18f2a2008-04-29 00:06:05 +0000672 if (!pCFileStruct->srch_inf.endOfSearch &&
673 !pCFileStruct->invalidHandle) {
674 pCFileStruct->invalidHandle = true;
Jeff Layton44772882010-10-15 15:34:03 -0400675 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000677 cFYI(1, "Closing uncompleted readdir with rc %d",
678 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 /* not much we can do if it fails anyway, ignore rc */
680 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000681 } else
Jeff Layton44772882010-10-15 15:34:03 -0400682 spin_unlock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
684 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000685 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000687 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000688 cifs_small_buf_release(ptmp);
689 else
690 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400692 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 kfree(file->private_data);
694 file->private_data = NULL;
695 }
696 /* BB can we lock the filestruct while this is going on? */
697 FreeXid(xid);
698 return rc;
699}
700
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000701static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
702 __u64 offset, __u8 lockType)
703{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000704 struct cifsLockInfo *li =
705 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000706 if (li == NULL)
707 return -ENOMEM;
708 li->offset = offset;
709 li->length = len;
710 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000711 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000712 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000713 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000714 return 0;
715}
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
718{
719 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 __u32 numLock = 0;
721 __u32 numUnlock = 0;
722 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000723 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000725 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000726 __u16 netfid;
727 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000728 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
730 length = 1 + pfLock->fl_end - pfLock->fl_start;
731 rc = -EACCES;
732 xid = GetXid();
733
Joe Perchesb6b38f72010-04-21 03:50:45 +0000734 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000736 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000737 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000740 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000742 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000744 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000745 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
747 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000748 cFYI(1, "Process suspended by mandatory locking - "
749 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000751 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000752 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 numLock = 1;
759 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000760 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000762 /* Check if unlock includes more than
763 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000765 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 lockType |= LOCKING_ANDX_SHARED_LOCK;
767 numLock = 1;
768 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000769 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 numLock = 1;
771 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000772 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 lockType |= LOCKING_ANDX_SHARED_LOCK;
774 numLock = 1;
775 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000776 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800778 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400779 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530782 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530784 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
Steve French08547b02006-02-28 22:39:25 +0000786 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Steve French13a6e422008-12-02 17:24:33 +0000788 if ((tcon->ses->capabilities & CAP_UNIX) &&
789 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000790 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000791 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000792 /* BB add code here to normalize offset and length to
793 account for negative length which we can not accept over the
794 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000796 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000797 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000798 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000799 posix_lock_type = CIFS_RDLCK;
800 else
801 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000802 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000803 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000804 posix_lock_type, wait_flag);
805 FreeXid(xid);
806 return rc;
807 }
808
809 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000810 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000811 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000813 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 pfLock->fl_start, 1 /* numUnlock */ ,
815 0 /* numLock */ , lockType,
816 0 /* wait flag */ );
817 pfLock->fl_type = F_UNLCK;
818 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000819 cERROR(1, "Error unlocking previously locked "
820 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 rc = 0;
822
823 } else {
824 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400825 rc = 0;
826
827 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
828 pfLock->fl_type = F_WRLCK;
829 } else {
830 rc = CIFSSMBLock(xid, tcon, netfid, length,
831 pfLock->fl_start, 0, 1,
832 lockType | LOCKING_ANDX_SHARED_LOCK,
833 0 /* wait flag */);
834 if (rc == 0) {
835 rc = CIFSSMBLock(xid, tcon, netfid,
836 length, pfLock->fl_start, 1, 0,
837 lockType |
838 LOCKING_ANDX_SHARED_LOCK,
839 0 /* wait flag */);
840 pfLock->fl_type = F_RDLCK;
841 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000842 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400843 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000844 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400845 rc = 0;
846 } else {
847 pfLock->fl_type = F_WRLCK;
848 rc = 0;
849 }
850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852
853 FreeXid(xid);
854 return rc;
855 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000856
857 if (!numLock && !numUnlock) {
858 /* if no lock or unlock then nothing
859 to do since we do not know what it is */
860 FreeXid(xid);
861 return -EOPNOTSUPP;
862 }
863
864 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000865 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000866 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000867 posix_lock_type = CIFS_RDLCK;
868 else
869 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000870
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000871 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000872 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000873
Steve French13a6e422008-12-02 17:24:33 +0000874 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000875 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000876 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000877 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700878 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000879
880 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000881 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000882 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 0, numLock, lockType, wait_flag);
884
885 if (rc == 0) {
886 /* For Windows locks we must store them. */
887 rc = store_file_lock(fid, length,
888 pfLock->fl_start, lockType);
889 }
890 } else if (numUnlock) {
891 /* For each stored lock that this unlock overlaps
892 completely, unlock it. */
893 int stored_rc = 0;
894 struct cifsLockInfo *li, *tmp;
895
Steve French6b70c952006-09-21 07:35:29 +0000896 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000897 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000898 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
899 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000900 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000901 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000902 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000903 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000905 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000906 if (stored_rc)
907 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000908 else {
909 list_del(&li->llist);
910 kfree(li);
911 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000912 }
913 }
Roland Dreier796e5662007-05-03 04:33:45 +0000914 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 }
916 }
917
Steve Frenchd634cc12005-08-26 14:42:59 -0500918 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 posix_lock_file_wait(file, pfLock);
920 FreeXid(xid);
921 return rc;
922}
923
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400924/*
925 * Set the timeout on write requests past EOF. For some servers (Windows)
926 * these calls can be very long.
927 *
928 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
929 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
930 * The 10M cutoff is totally arbitrary. A better scheme for this would be
931 * welcome if someone wants to suggest one.
932 *
933 * We may be able to do a better job with this if there were some way to
934 * declare that a file should be sparse.
935 */
936static int
937cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
938{
939 if (offset <= cifsi->server_eof)
940 return CIFS_STD_OP;
941 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
942 return CIFS_VLONG_OP;
943 else
944 return CIFS_LONG_OP;
945}
946
947/* update the file size (if needed) after a write */
948static void
949cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
950 unsigned int bytes_written)
951{
952 loff_t end_of_write = offset + bytes_written;
953
954 if (end_of_write > cifsi->server_eof)
955 cifsi->server_eof = end_of_write;
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958ssize_t cifs_user_write(struct file *file, const char __user *write_data,
959 size_t write_size, loff_t *poffset)
960{
961 int rc = 0;
962 unsigned int bytes_written = 0;
963 unsigned int total_written;
964 struct cifs_sb_info *cifs_sb;
965 struct cifsTconInfo *pTcon;
966 int xid, long_op;
967 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400968 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800970 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Joe Perchesb6b38f72010-04-21 03:50:45 +0000972 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
973 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 if (file->private_data == NULL)
976 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700977
Joe Perchesc21dfb62010-07-12 13:50:14 -0700978 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400979 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000980
Jeff Layton838726c2008-08-28 07:54:59 -0400981 rc = generic_write_checks(file, poffset, &write_size, 0);
982 if (rc)
983 return rc;
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400987 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 for (total_written = 0; write_size > total_written;
989 total_written += bytes_written) {
990 rc = -EAGAIN;
991 while (rc == -EAGAIN) {
992 if (file->private_data == NULL) {
993 /* file has been closed on us */
994 FreeXid(xid);
995 /* if we have gotten here we have written some data
996 and blocked, and the file has been freed on us while
997 we blocked so return what we managed to write */
998 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 /* we could deadlock if we called
1002 filemap_fdatawait from here so tell
1003 reopen_file not to flush data to server
1004 now */
Jeff Layton15886172010-10-15 15:33:59 -04001005 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (rc != 0)
1007 break;
1008 }
1009
1010 rc = CIFSSMBWrite(xid, pTcon,
1011 open_file->netfid,
1012 min_t(const int, cifs_sb->wsize,
1013 write_size - total_written),
1014 *poffset, &bytes_written,
1015 NULL, write_data + total_written, long_op);
1016 }
1017 if (rc || (bytes_written == 0)) {
1018 if (total_written)
1019 break;
1020 else {
1021 FreeXid(xid);
1022 return rc;
1023 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001024 } else {
1025 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001027 }
Steve French133672e2007-11-13 22:41:37 +00001028 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 15 seconds is plenty */
1030 }
1031
Steve Frencha4544342005-08-24 13:59:35 -07001032 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001035 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1036 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001037/* Do not update local mtime - server will set its actual value on write
1038 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001039 * current_fs_time(inode->i_sb);*/
1040 if (total_written > 0) {
1041 spin_lock(&inode->i_lock);
1042 if (*poffset > file->f_path.dentry->d_inode->i_size)
1043 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001045 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001047 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 }
1049 FreeXid(xid);
1050 return total_written;
1051}
1052
Jeff Layton7da4b492010-10-15 15:34:00 -04001053static ssize_t cifs_write(struct cifsFileInfo *open_file,
1054 const char *write_data, size_t write_size,
1055 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
1057 int rc = 0;
1058 unsigned int bytes_written = 0;
1059 unsigned int total_written;
1060 struct cifs_sb_info *cifs_sb;
1061 struct cifsTconInfo *pTcon;
1062 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001063 struct dentry *dentry = open_file->dentry;
1064 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Jeff Layton7da4b492010-10-15 15:34:00 -04001066 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Joe Perchesb6b38f72010-04-21 03:50:45 +00001068 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001069 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Jeff Layton13cfb732010-09-29 19:51:11 -04001071 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001075 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 for (total_written = 0; write_size > total_written;
1077 total_written += bytes_written) {
1078 rc = -EAGAIN;
1079 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 /* we could deadlock if we called
1082 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001083 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001085 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 if (rc != 0)
1087 break;
1088 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001089 if (experimEnabled || (pTcon->ses->server &&
1090 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001091 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001092 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001093 struct kvec iov[2];
1094 unsigned int len;
1095
Steve French0ae0efa2005-10-10 10:57:19 -07001096 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001097 write_size - total_written);
1098 /* iov[0] is reserved for smb header */
1099 iov[1].iov_base = (char *)write_data +
1100 total_written;
1101 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001102 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001103 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001104 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001105 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001106 } else
Steve French60808232006-04-22 15:53:05 +00001107 rc = CIFSSMBWrite(xid, pTcon,
1108 open_file->netfid,
1109 min_t(const int, cifs_sb->wsize,
1110 write_size - total_written),
1111 *poffset, &bytes_written,
1112 write_data + total_written,
1113 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 if (rc || (bytes_written == 0)) {
1116 if (total_written)
1117 break;
1118 else {
1119 FreeXid(xid);
1120 return rc;
1121 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001122 } else {
1123 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001125 }
Steve French133672e2007-11-13 22:41:37 +00001126 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 15 seconds is plenty */
1128 }
1129
Steve Frencha4544342005-08-24 13:59:35 -07001130 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Jeff Layton7da4b492010-10-15 15:34:00 -04001132 if (total_written > 0) {
1133 spin_lock(&dentry->d_inode->i_lock);
1134 if (*poffset > dentry->d_inode->i_size)
1135 i_size_write(dentry->d_inode, *poffset);
1136 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001138 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 FreeXid(xid);
1140 return total_written;
1141}
1142
Steve French630f3f0c2007-10-25 21:17:17 +00001143#ifdef CONFIG_CIFS_EXPERIMENTAL
Jeff Layton6508d902010-09-29 19:51:11 -04001144struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1145 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001146{
1147 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001148 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1149
1150 /* only filter by fsuid on multiuser mounts */
1151 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1152 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001153
Jeff Layton44772882010-10-15 15:34:03 -04001154 spin_lock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001155 /* we could simply get the first_list_entry since write-only entries
1156 are always at the end of the list but since the first entry might
1157 have a close pending, we go through the whole list */
1158 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001159 if (fsuid_only && open_file->uid != current_fsuid())
1160 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001161 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001162 if (!open_file->invalidHandle) {
1163 /* found a good file */
1164 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001165 cifsFileInfo_get(open_file);
Jeff Layton44772882010-10-15 15:34:03 -04001166 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001167 return open_file;
1168 } /* else might as well continue, and look for
1169 another, or simply have the caller reopen it
1170 again rather than trying to fix this handle */
1171 } else /* write only file */
1172 break; /* write only files are last so must be done */
1173 }
Jeff Layton44772882010-10-15 15:34:03 -04001174 spin_unlock(&cifs_file_list_lock);
Steve French630f3f0c2007-10-25 21:17:17 +00001175 return NULL;
1176}
1177#endif
1178
Jeff Layton6508d902010-09-29 19:51:11 -04001179struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1180 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001181{
1182 struct cifsFileInfo *open_file;
Jeff Layton6508d902010-09-29 19:51:11 -04001183 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
Jeff Layton2846d382008-09-22 21:33:33 -04001184 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001185 int rc;
Steve French6148a742005-10-05 12:23:19 -07001186
Steve French60808232006-04-22 15:53:05 +00001187 /* Having a null inode here (because mapping->host was set to zero by
1188 the VFS or MM) should not happen but we had reports of on oops (due to
1189 it being zero) during stress testcases so we need to check for it */
1190
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001191 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001192 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001193 dump_stack();
1194 return NULL;
1195 }
1196
Jeff Layton6508d902010-09-29 19:51:11 -04001197 /* only filter by fsuid on multiuser mounts */
1198 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1199 fsuid_only = false;
1200
Jeff Layton44772882010-10-15 15:34:03 -04001201 spin_lock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001202refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001203 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001204 if (!any_available && open_file->pid != current->tgid)
1205 continue;
1206 if (fsuid_only && open_file->uid != current_fsuid())
1207 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001208 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001209 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001210
1211 if (!open_file->invalidHandle) {
1212 /* found a good writable file */
Jeff Layton44772882010-10-15 15:34:03 -04001213 spin_unlock(&cifs_file_list_lock);
Steve French9b22b0b2007-10-02 01:11:08 +00001214 return open_file;
1215 }
Steve French8840dee2007-11-16 23:05:52 +00001216
Jeff Layton44772882010-10-15 15:34:03 -04001217 spin_unlock(&cifs_file_list_lock);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001218
Steve French9b22b0b2007-10-02 01:11:08 +00001219 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001220 rc = cifs_reopen_file(open_file, false);
Steve Frenchcdff08e2010-10-21 22:46:14 +00001221 if (!rc)
1222 return open_file;
Steve French9b22b0b2007-10-02 01:11:08 +00001223
Steve Frenchcdff08e2010-10-21 22:46:14 +00001224 /* if it fails, try another handle if possible */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001225 cFYI(1, "wp failed on reopen file");
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001226 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001227
Steve Frenchcdff08e2010-10-21 22:46:14 +00001228 spin_lock(&cifs_file_list_lock);
1229
Steve French9b22b0b2007-10-02 01:11:08 +00001230 /* else we simply continue to the next entry. Thus
1231 we do not loop on reopen errors. If we
1232 can not reopen the file, for example if we
1233 reconnected to a server with another client
1234 racing to delete or lock the file we would not
1235 make progress if we restarted before the beginning
1236 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001237 }
1238 }
Jeff Layton2846d382008-09-22 21:33:33 -04001239 /* couldn't find useable FH with same pid, try any available */
1240 if (!any_available) {
1241 any_available = true;
1242 goto refind_writable;
1243 }
Jeff Layton44772882010-10-15 15:34:03 -04001244 spin_unlock(&cifs_file_list_lock);
Steve French6148a742005-10-05 12:23:19 -07001245 return NULL;
1246}
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1249{
1250 struct address_space *mapping = page->mapping;
1251 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1252 char *write_data;
1253 int rc = -EFAULT;
1254 int bytes_written = 0;
1255 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001257 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259 if (!mapping || !mapping->host)
1260 return -EFAULT;
1261
1262 inode = page->mapping->host;
1263 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 offset += (loff_t)from;
1266 write_data = kmap(page);
1267 write_data += from;
1268
1269 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1270 kunmap(page);
1271 return -EIO;
1272 }
1273
1274 /* racing with truncate? */
1275 if (offset > mapping->host->i_size) {
1276 kunmap(page);
1277 return 0; /* don't care */
1278 }
1279
1280 /* check to make sure that we are not extending the file */
1281 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001282 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Jeff Layton6508d902010-09-29 19:51:11 -04001284 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001285 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001286 bytes_written = cifs_write(open_file, write_data,
1287 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001288 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001290 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001291 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001292 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001293 else if (bytes_written < 0)
1294 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001295 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001296 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 rc = -EIO;
1298 }
1299
1300 kunmap(page);
1301 return rc;
1302}
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001305 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Steve French37c0eb42005-10-05 14:50:29 -07001307 struct backing_dev_info *bdi = mapping->backing_dev_info;
1308 unsigned int bytes_to_write;
1309 unsigned int bytes_written;
1310 struct cifs_sb_info *cifs_sb;
1311 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001312 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001313 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001314 int range_whole = 0;
1315 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001316 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001317 int n_iov = 0;
1318 pgoff_t next;
1319 int nr_pages;
1320 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001321 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001322 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001323 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001324 struct page *page;
1325 struct pagevec pvec;
1326 int rc = 0;
1327 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001328 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
Jeff Laytonf3983c22010-09-22 16:17:40 -07001330 /*
1331 * BB: Is this meaningful for a non-block-device file system?
1332 * If it is, we should test it again after we do I/O
1333 */
1334 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1335 wbc->encountered_congestion = 1;
1336 return 0;
1337 }
1338
Steve French37c0eb42005-10-05 14:50:29 -07001339 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001340
Steve French37c0eb42005-10-05 14:50:29 -07001341 /*
1342 * If wsize is smaller that the page cache size, default to writing
1343 * one page at a time via cifs_writepage
1344 */
1345 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1346 return generic_writepages(mapping, wbc);
1347
Steve French9a0c8232007-02-02 04:21:57 +00001348 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001349 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001350 return generic_writepages(mapping, wbc);
1351
Steve French37c0eb42005-10-05 14:50:29 -07001352 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001353 * if there's no open file, then this is likely to fail too,
1354 * but it'll at least handle the return. Maybe it should be
1355 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001356 */
Jeff Layton6508d902010-09-29 19:51:11 -04001357 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001358 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001359 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001360 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001361 }
1362
Jeff Layton13cfb732010-09-29 19:51:11 -04001363 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001364 if (!experimEnabled && tcon->ses->server->secMode &
1365 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1366 cifsFileInfo_put(open_file);
1367 return generic_writepages(mapping, wbc);
1368 }
1369 cifsFileInfo_put(open_file);
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 xid = GetXid();
1372
Steve French37c0eb42005-10-05 14:50:29 -07001373 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001374 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001375 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001376 end = -1;
1377 } else {
1378 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1379 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1380 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1381 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001382 scanned = 1;
1383 }
1384retry:
1385 while (!done && (index <= end) &&
1386 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1387 PAGECACHE_TAG_DIRTY,
1388 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1389 int first;
1390 unsigned int i;
1391
Steve French37c0eb42005-10-05 14:50:29 -07001392 first = -1;
1393 next = 0;
1394 n_iov = 0;
1395 bytes_to_write = 0;
1396
1397 for (i = 0; i < nr_pages; i++) {
1398 page = pvec.pages[i];
1399 /*
1400 * At this point we hold neither mapping->tree_lock nor
1401 * lock on the page itself: the page may be truncated or
1402 * invalidated (changing page->mapping to NULL), or even
1403 * swizzled back from swapper_space to tmpfs file
1404 * mapping
1405 */
1406
1407 if (first < 0)
1408 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001409 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001410 break;
1411
1412 if (unlikely(page->mapping != mapping)) {
1413 unlock_page(page);
1414 break;
1415 }
1416
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001417 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001418 done = 1;
1419 unlock_page(page);
1420 break;
1421 }
1422
1423 if (next && (page->index != next)) {
1424 /* Not next consecutive page */
1425 unlock_page(page);
1426 break;
1427 }
1428
1429 if (wbc->sync_mode != WB_SYNC_NONE)
1430 wait_on_page_writeback(page);
1431
1432 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001433 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001434 unlock_page(page);
1435 break;
1436 }
Steve French84d2f072005-10-12 15:32:05 -07001437
Linus Torvaldscb876f42006-12-23 16:19:07 -08001438 /*
1439 * This actually clears the dirty bit in the radix tree.
1440 * See cifs_writepage() for more commentary.
1441 */
1442 set_page_writeback(page);
1443
Steve French84d2f072005-10-12 15:32:05 -07001444 if (page_offset(page) >= mapping->host->i_size) {
1445 done = 1;
1446 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001447 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001448 break;
1449 }
1450
Steve French37c0eb42005-10-05 14:50:29 -07001451 /*
1452 * BB can we get rid of this? pages are held by pvec
1453 */
1454 page_cache_get(page);
1455
Steve French84d2f072005-10-12 15:32:05 -07001456 len = min(mapping->host->i_size - page_offset(page),
1457 (loff_t)PAGE_CACHE_SIZE);
1458
Steve French37c0eb42005-10-05 14:50:29 -07001459 /* reserve iov[0] for the smb header */
1460 n_iov++;
1461 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001462 iov[n_iov].iov_len = len;
1463 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001464
1465 if (first < 0) {
1466 first = i;
1467 offset = page_offset(page);
1468 }
1469 next = page->index + 1;
1470 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1471 break;
1472 }
1473 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001474 open_file = find_writable_file(CIFS_I(mapping->host),
1475 false);
Steve French23e7dd72005-10-20 13:44:56 -07001476 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001477 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001478 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001479 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001480 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001481 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001482 bytes_to_write, offset,
1483 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001484 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001485 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001486 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001487 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001488
1489 if (rc || bytes_written < bytes_to_write) {
1490 cERROR(1, "Write2 ret %d, wrote %d",
1491 rc, bytes_written);
1492 /* BB what if continued retry is
1493 requested via mount flags? */
1494 if (rc == -ENOSPC)
1495 set_bit(AS_ENOSPC, &mapping->flags);
1496 else
1497 set_bit(AS_EIO, &mapping->flags);
1498 } else {
1499 cifs_stats_bytes_written(tcon, bytes_written);
1500 }
1501
Steve French37c0eb42005-10-05 14:50:29 -07001502 for (i = 0; i < n_iov; i++) {
1503 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001504 /* Should we also set page error on
1505 success rc but too little data written? */
1506 /* BB investigate retry logic on temporary
1507 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001508 when page marked as error */
1509 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001510 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001511 kunmap(page);
1512 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001513 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001514 page_cache_release(page);
1515 }
1516 if ((wbc->nr_to_write -= n_iov) <= 0)
1517 done = 1;
1518 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001519 } else
1520 /* Need to re-find the pages we skipped */
1521 index = pvec.pages[0]->index + 1;
1522
Steve French37c0eb42005-10-05 14:50:29 -07001523 pagevec_release(&pvec);
1524 }
1525 if (!scanned && !done) {
1526 /*
1527 * We hit the last page and there is more work to be done: wrap
1528 * back to the start of the file
1529 */
1530 scanned = 1;
1531 index = 0;
1532 goto retry;
1533 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001534 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001535 mapping->writeback_index = index;
1536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001538 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 return rc;
1540}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001542static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544 int rc = -EFAULT;
1545 int xid;
1546
1547 xid = GetXid();
1548/* BB add check for wbc flags */
1549 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001550 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001551 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001552
1553 /*
1554 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1555 *
1556 * A writepage() implementation always needs to do either this,
1557 * or re-dirty the page with "redirty_page_for_writepage()" in
1558 * the case of a failure.
1559 *
1560 * Just unlocking the page will cause the radix tree tag-bits
1561 * to fail to update with the state of the page correctly.
1562 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001563 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1565 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1566 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001567 end_page_writeback(page);
1568 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 FreeXid(xid);
1570 return rc;
1571}
1572
Nick Piggind9414772008-09-24 11:32:59 -04001573static int cifs_write_end(struct file *file, struct address_space *mapping,
1574 loff_t pos, unsigned len, unsigned copied,
1575 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576{
Nick Piggind9414772008-09-24 11:32:59 -04001577 int rc;
1578 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Joe Perchesb6b38f72010-04-21 03:50:45 +00001580 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1581 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001582
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001583 if (PageChecked(page)) {
1584 if (copied == len)
1585 SetPageUptodate(page);
1586 ClearPageChecked(page);
1587 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001588 SetPageUptodate(page);
1589
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001591 char *page_data;
1592 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1593 int xid;
1594
1595 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 /* this is probably better than directly calling
1597 partialpage_write since in this function the file handle is
1598 known which we might as well leverage */
1599 /* BB check if anything else missing out of ppw
1600 such as updating last write time */
1601 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001602 rc = cifs_write(file->private_data, page_data + offset,
1603 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001604 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001606
1607 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001608 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001609 rc = copied;
1610 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 set_page_dirty(page);
1612 }
1613
Nick Piggind9414772008-09-24 11:32:59 -04001614 if (rc > 0) {
1615 spin_lock(&inode->i_lock);
1616 if (pos > inode->i_size)
1617 i_size_write(inode, pos);
1618 spin_unlock(&inode->i_lock);
1619 }
1620
1621 unlock_page(page);
1622 page_cache_release(page);
1623
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return rc;
1625}
1626
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001627int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
1629 int xid;
1630 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001631 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001632 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001633 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635 xid = GetXid();
1636
Joe Perchesb6b38f72010-04-21 03:50:45 +00001637 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001638 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001639
Jeff Laytoncea21802007-11-20 23:19:03 +00001640 rc = filemap_write_and_wait(inode->i_mapping);
1641 if (rc == 0) {
1642 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 CIFS_I(inode)->write_behind_rc = 0;
Jeff Layton13cfb732010-09-29 19:51:11 -04001644 tcon = tlink_tcon(smbfile->tlink);
Steve Frenchbe652442009-02-23 15:21:59 +00001645 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001646 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001647 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001648 }
Steve Frenchb298f222009-02-21 21:17:43 +00001649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 FreeXid(xid);
1651 return rc;
1652}
1653
NeilBrown3978d7172006-03-26 01:37:17 -08001654/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
1656 struct address_space *mapping;
1657 struct inode *inode;
1658 unsigned long index = page->index;
1659 unsigned int rpages = 0;
1660 int rc = 0;
1661
Steve Frenchf19159d2010-04-21 04:12:10 +00001662 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 mapping = page->mapping;
1664 if (!mapping)
1665 return 0;
1666 inode = mapping->host;
1667 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001668 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001670/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1672
Joe Perchesb6b38f72010-04-21 03:50:45 +00001673/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
NeilBrown3978d7172006-03-26 01:37:17 -08001675#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 if (rc < 0)
1677 return rc;
1678 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001679#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680} */
1681
1682/*
1683 * As file closes, flush all cached write data for this inode checking
1684 * for write behind errors.
1685 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001686int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001688 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 int rc = 0;
1690
1691 /* Rather than do the steps manually:
1692 lock the inode for writing
1693 loop through pages looking for write behind data (dirty pages)
1694 coalesce into contiguous 16K (or smaller) chunks to write to server
1695 send to server (prefer in parallel)
1696 deal with writebehind errors
1697 unlock inode for writing
1698 filemapfdatawrite appears easier for the time being */
1699
1700 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001701 /* reset wb rc if we were able to write out dirty pages */
1702 if (!rc) {
1703 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001705 }
Steve French50c2f752007-07-13 00:33:32 +00001706
Joe Perchesb6b38f72010-04-21 03:50:45 +00001707 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 return rc;
1710}
1711
1712ssize_t cifs_user_read(struct file *file, char __user *read_data,
1713 size_t read_size, loff_t *poffset)
1714{
1715 int rc = -EACCES;
1716 unsigned int bytes_read = 0;
1717 unsigned int total_read = 0;
1718 unsigned int current_read_size;
1719 struct cifs_sb_info *cifs_sb;
1720 struct cifsTconInfo *pTcon;
1721 int xid;
1722 struct cifsFileInfo *open_file;
1723 char *smb_read_data;
1724 char __user *current_offset;
1725 struct smb_com_read_rsp *pSMBr;
1726
1727 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001728 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301731 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301733 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001735 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001736 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve Frenchad7a2922008-02-07 23:25:02 +00001738 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001739 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001740
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 for (total_read = 0, current_offset = read_data;
1742 read_size > total_read;
1743 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001744 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 cifs_sb->rsize);
1746 rc = -EAGAIN;
1747 smb_read_data = NULL;
1748 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001749 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001750 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001751 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 if (rc != 0)
1753 break;
1754 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001755 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001756 open_file->netfid,
1757 current_read_size, *poffset,
1758 &bytes_read, &smb_read_data,
1759 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001762 if (copy_to_user(current_offset,
1763 smb_read_data +
1764 4 /* RFC1001 length field */ +
1765 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001766 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001767 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001768
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001769 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001770 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001771 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001772 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 smb_read_data = NULL;
1774 }
1775 }
1776 if (rc || (bytes_read == 0)) {
1777 if (total_read) {
1778 break;
1779 } else {
1780 FreeXid(xid);
1781 return rc;
1782 }
1783 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001784 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 *poffset += bytes_read;
1786 }
1787 }
1788 FreeXid(xid);
1789 return total_read;
1790}
1791
1792
1793static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1794 loff_t *poffset)
1795{
1796 int rc = -EACCES;
1797 unsigned int bytes_read = 0;
1798 unsigned int total_read;
1799 unsigned int current_read_size;
1800 struct cifs_sb_info *cifs_sb;
1801 struct cifsTconInfo *pTcon;
1802 int xid;
1803 char *current_offset;
1804 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001805 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001808 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
1810 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301811 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301813 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001815 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001816 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001819 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 read_size > total_read;
1823 total_read += bytes_read, current_offset += bytes_read) {
1824 current_read_size = min_t(const int, read_size - total_read,
1825 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001826 /* For windows me and 9x we do not want to request more
1827 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001828 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001829 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1830 current_read_size = min_t(const int, current_read_size,
1831 pTcon->ses->server->maxBuf - 128);
1832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 rc = -EAGAIN;
1834 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001835 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001836 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 if (rc != 0)
1838 break;
1839 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001840 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001841 open_file->netfid,
1842 current_read_size, *poffset,
1843 &bytes_read, &current_offset,
1844 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
1846 if (rc || (bytes_read == 0)) {
1847 if (total_read) {
1848 break;
1849 } else {
1850 FreeXid(xid);
1851 return rc;
1852 }
1853 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001854 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 *poffset += bytes_read;
1856 }
1857 }
1858 FreeXid(xid);
1859 return total_read;
1860}
1861
1862int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1863{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 int rc, xid;
1865
1866 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001867 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001869 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 FreeXid(xid);
1871 return rc;
1872 }
1873 rc = generic_file_mmap(file, vma);
1874 FreeXid(xid);
1875 return rc;
1876}
1877
1878
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001879static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001880 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881{
1882 struct page *page;
1883 char *target;
1884
1885 while (bytes_read > 0) {
1886 if (list_empty(pages))
1887 break;
1888
1889 page = list_entry(pages->prev, struct page, lru);
1890 list_del(&page->lru);
1891
Nick Piggin315e9952010-04-21 03:18:28 +00001892 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 GFP_KERNEL)) {
1894 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001895 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001896 data += PAGE_CACHE_SIZE;
1897 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 continue;
1899 }
Jeff Layton06b43672010-06-01 10:54:45 -04001900 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 if (PAGE_CACHE_SIZE > bytes_read) {
1905 memcpy(target, data, bytes_read);
1906 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001907 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 PAGE_CACHE_SIZE - bytes_read);
1909 bytes_read = 0;
1910 } else {
1911 memcpy(target, data, PAGE_CACHE_SIZE);
1912 bytes_read -= PAGE_CACHE_SIZE;
1913 }
1914 kunmap_atomic(target, KM_USER0);
1915
1916 flush_dcache_page(page);
1917 SetPageUptodate(page);
1918 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301920
1921 /* add page to FS-Cache */
1922 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924 return;
1925}
1926
1927static int cifs_readpages(struct file *file, struct address_space *mapping,
1928 struct list_head *page_list, unsigned num_pages)
1929{
1930 int rc = -EACCES;
1931 int xid;
1932 loff_t offset;
1933 struct page *page;
1934 struct cifs_sb_info *cifs_sb;
1935 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001936 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001937 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 char *smb_read_data = NULL;
1939 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001941 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943 xid = GetXid();
1944 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301945 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301947 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001949 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001950 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001951 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001952
Suresh Jayaraman56698232010-07-05 18:13:25 +05301953 /*
1954 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1955 * immediately if the cookie is negative
1956 */
1957 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1958 &num_pages);
1959 if (rc == 0)
1960 goto read_complete;
1961
Steve Frenchf19159d2010-04-21 04:12:10 +00001962 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 for (i = 0; i < num_pages; ) {
1964 unsigned contig_pages;
1965 struct page *tmp_page;
1966 unsigned long expected_index;
1967
1968 if (list_empty(page_list))
1969 break;
1970
1971 page = list_entry(page_list->prev, struct page, lru);
1972 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1973
1974 /* count adjacent pages that we will read into */
1975 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001978 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 if (tmp_page->index == expected_index) {
1980 contig_pages++;
1981 expected_index++;
1982 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001983 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
1985 if (contig_pages + i > num_pages)
1986 contig_pages = num_pages - i;
1987
1988 /* for reads over a certain size could initiate async
1989 read ahead */
1990
1991 read_size = contig_pages * PAGE_CACHE_SIZE;
1992 /* Read size needs to be in multiples of one page */
1993 read_size = min_t(const unsigned int, read_size,
1994 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001995 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1996 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 rc = -EAGAIN;
1998 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001999 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04002000 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 if (rc != 0)
2002 break;
2003 }
2004
Steve Frenchbfa0d752005-08-31 21:50:37 -07002005 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002006 open_file->netfid,
2007 read_size, offset,
2008 &bytes_read, &smb_read_data,
2009 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002010 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002011 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002013 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002014 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002015 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002016 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 smb_read_data = NULL;
2018 }
2019 }
2020 }
2021 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002022 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 break;
2024 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002025 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2027 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2028 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002029 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002032 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002033 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 i++; /* account for partial page */
2035
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002038 /* BB do we need to verify this common case ?
2039 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 we will hit it on next read */
2041
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002042 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 }
2044 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002045 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002046 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002047 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 break;
2051 }
2052 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002053 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002054 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002055 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002056 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 smb_read_data = NULL;
2058 }
2059 bytes_read = 0;
2060 }
2061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062/* need to free smb_read_data buf before exit */
2063 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002064 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002065 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002067 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Suresh Jayaraman56698232010-07-05 18:13:25 +05302071read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 FreeXid(xid);
2073 return rc;
2074}
2075
2076static int cifs_readpage_worker(struct file *file, struct page *page,
2077 loff_t *poffset)
2078{
2079 char *read_data;
2080 int rc;
2081
Suresh Jayaraman56698232010-07-05 18:13:25 +05302082 /* Is the page cached? */
2083 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2084 if (rc == 0)
2085 goto read_complete;
2086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 page_cache_get(page);
2088 read_data = kmap(page);
2089 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 if (rc < 0)
2094 goto io_error;
2095 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002096 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002097
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002098 file->f_path.dentry->d_inode->i_atime =
2099 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002100
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 if (PAGE_CACHE_SIZE > rc)
2102 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2103
2104 flush_dcache_page(page);
2105 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302106
2107 /* send this page to the cache */
2108 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002111
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002113 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302115
2116read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 return rc;
2118}
2119
2120static int cifs_readpage(struct file *file, struct page *page)
2121{
2122 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2123 int rc = -EACCES;
2124 int xid;
2125
2126 xid = GetXid();
2127
2128 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302129 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302131 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
2133
Joe Perchesb6b38f72010-04-21 03:50:45 +00002134 cFYI(1, "readpage %p at offset %d 0x%x\n",
2135 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
2137 rc = cifs_readpage_worker(file, page, &offset);
2138
2139 unlock_page(page);
2140
2141 FreeXid(xid);
2142 return rc;
2143}
2144
Steve Frencha403a0a2007-07-26 15:54:16 +00002145static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2146{
2147 struct cifsFileInfo *open_file;
2148
Jeff Layton44772882010-10-15 15:34:03 -04002149 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002150 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002151 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002152 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002153 return 1;
2154 }
2155 }
Jeff Layton44772882010-10-15 15:34:03 -04002156 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002157 return 0;
2158}
2159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160/* We do not want to update the file size from server for inodes
2161 open for write - to avoid races with writepage extending
2162 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002163 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 but this is tricky to do without racing with writebehind
2165 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002166bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167{
Steve Frencha403a0a2007-07-26 15:54:16 +00002168 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002169 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002170
Steve Frencha403a0a2007-07-26 15:54:16 +00002171 if (is_inode_writable(cifsInode)) {
2172 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002173 struct cifs_sb_info *cifs_sb;
2174
Steve Frenchc32a0b62006-01-12 14:41:28 -08002175 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002176 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002177 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002178 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002179 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002180 }
2181
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002182 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002183 return true;
Steve French7ba52632007-02-08 18:14:13 +00002184
Steve French4b18f2a2008-04-29 00:06:05 +00002185 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002186 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002187 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188}
2189
Nick Piggind9414772008-09-24 11:32:59 -04002190static int cifs_write_begin(struct file *file, struct address_space *mapping,
2191 loff_t pos, unsigned len, unsigned flags,
2192 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
Nick Piggind9414772008-09-24 11:32:59 -04002194 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2195 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002196 loff_t page_start = pos & PAGE_MASK;
2197 loff_t i_size;
2198 struct page *page;
2199 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Joe Perchesb6b38f72010-04-21 03:50:45 +00002201 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002202
Nick Piggin54566b22009-01-04 12:00:53 -08002203 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002204 if (!page) {
2205 rc = -ENOMEM;
2206 goto out;
2207 }
Nick Piggind9414772008-09-24 11:32:59 -04002208
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002209 if (PageUptodate(page))
2210 goto out;
Steve French8a236262007-03-06 00:31:00 +00002211
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002212 /*
2213 * If we write a full page it will be up to date, no need to read from
2214 * the server. If the write is short, we'll end up doing a sync write
2215 * instead.
2216 */
2217 if (len == PAGE_CACHE_SIZE)
2218 goto out;
2219
2220 /*
2221 * optimize away the read when we have an oplock, and we're not
2222 * expecting to use any of the data we'd be reading in. That
2223 * is, when the page lies beyond the EOF, or straddles the EOF
2224 * and the write will cover all of the existing data.
2225 */
2226 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2227 i_size = i_size_read(mapping->host);
2228 if (page_start >= i_size ||
2229 (offset == 0 && (pos + len) >= i_size)) {
2230 zero_user_segments(page, 0, offset,
2231 offset + len,
2232 PAGE_CACHE_SIZE);
2233 /*
2234 * PageChecked means that the parts of the page
2235 * to which we're not writing are considered up
2236 * to date. Once the data is copied to the
2237 * page, it can be set uptodate.
2238 */
2239 SetPageChecked(page);
2240 goto out;
2241 }
2242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
Nick Piggind9414772008-09-24 11:32:59 -04002244 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002245 /*
2246 * might as well read a page, it is fast enough. If we get
2247 * an error, we don't need to return it. cifs_write_end will
2248 * do a sync write instead since PG_uptodate isn't set.
2249 */
2250 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002251 } else {
2252 /* we could try using another file handle if there is one -
2253 but how would we lock it to prevent close of that handle
2254 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002255 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002256 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002257out:
2258 *pagep = page;
2259 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260}
2261
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302262static int cifs_release_page(struct page *page, gfp_t gfp)
2263{
2264 if (PagePrivate(page))
2265 return 0;
2266
2267 return cifs_fscache_release_page(page, gfp);
2268}
2269
2270static void cifs_invalidate_page(struct page *page, unsigned long offset)
2271{
2272 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2273
2274 if (offset == 0)
2275 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2276}
2277
Tejun Heo9b646972010-07-20 22:09:02 +02002278void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002279{
2280 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2281 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002282 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002283 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002284 int rc, waitrc = 0;
2285
2286 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002287 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002288 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002289 else
Al Viro8737c932009-12-24 06:47:55 -05002290 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002291 rc = filemap_fdatawrite(inode->i_mapping);
2292 if (cinode->clientCanCacheRead == 0) {
2293 waitrc = filemap_fdatawait(inode->i_mapping);
2294 invalidate_remote_inode(inode);
2295 }
2296 if (!rc)
2297 rc = waitrc;
2298 if (rc)
2299 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002300 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002301 }
2302
2303 /*
2304 * releasing stale oplock after recent reconnect of smb session using
2305 * a now incorrect file handle is not a data integrity issue but do
2306 * not bother sending an oplock release if session to server still is
2307 * disconnected since oplock already released by the server
2308 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002309 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002310 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2311 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002312 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002313 }
Tejun Heo9b646972010-07-20 22:09:02 +02002314
2315 /*
2316 * We might have kicked in before is_valid_oplock_break()
2317 * finished grabbing reference for us. Make sure it's done by
2318 * waiting for GlobalSMSSeslock.
2319 */
Jeff Layton44772882010-10-15 15:34:03 -04002320 spin_lock(&cifs_file_list_lock);
2321 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002322
2323 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002324}
2325
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002326/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002327void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002328{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002329 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002330 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002331}
2332
Tejun Heo9b646972010-07-20 22:09:02 +02002333void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002334{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002335 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002336 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002337}
2338
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002339const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 .readpage = cifs_readpage,
2341 .readpages = cifs_readpages,
2342 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002343 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002344 .write_begin = cifs_write_begin,
2345 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302347 .releasepage = cifs_release_page,
2348 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 /* .sync_page = cifs_sync_page, */
2350 /* .direct_IO = */
2351};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002352
2353/*
2354 * cifs_readpages requires the server to support a buffer large enough to
2355 * contain the header plus one complete page of data. Otherwise, we need
2356 * to leave cifs_readpages out of the address space operations.
2357 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002358const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002359 .readpage = cifs_readpage,
2360 .writepage = cifs_writepage,
2361 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002362 .write_begin = cifs_write_begin,
2363 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002364 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302365 .releasepage = cifs_release_page,
2366 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002367 /* .sync_page = cifs_sync_page, */
2368 /* .direct_IO = */
2369};