blob: 128e07b85d6cb28610ded1f934471b8d64049189 [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
Jeff Laytond3f13222010-10-15 15:34:07 -04001691 if (file->f_mode & FMODE_WRITE) {
1692 rc = filemap_write_and_wait(inode->i_mapping);
1693 /* reset wb rc if we were able to write out dirty pages */
1694 if (!rc) {
1695 rc = CIFS_I(inode)->write_behind_rc;
1696 CIFS_I(inode)->write_behind_rc = 0;
1697 }
Jeff Laytoncea21802007-11-20 23:19:03 +00001698 }
Steve French50c2f752007-07-13 00:33:32 +00001699
Joe Perchesb6b38f72010-04-21 03:50:45 +00001700 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702 return rc;
1703}
1704
1705ssize_t cifs_user_read(struct file *file, char __user *read_data,
1706 size_t read_size, loff_t *poffset)
1707{
1708 int rc = -EACCES;
1709 unsigned int bytes_read = 0;
1710 unsigned int total_read = 0;
1711 unsigned int current_read_size;
1712 struct cifs_sb_info *cifs_sb;
1713 struct cifsTconInfo *pTcon;
1714 int xid;
1715 struct cifsFileInfo *open_file;
1716 char *smb_read_data;
1717 char __user *current_offset;
1718 struct smb_com_read_rsp *pSMBr;
1719
1720 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001721 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301724 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301726 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001728 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001729 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Steve Frenchad7a2922008-02-07 23:25:02 +00001731 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001732 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001733
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 for (total_read = 0, current_offset = read_data;
1735 read_size > total_read;
1736 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 cifs_sb->rsize);
1739 rc = -EAGAIN;
1740 smb_read_data = NULL;
1741 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001742 int buf_type = CIFS_NO_BUFFER;
Steve Frenchcdff08e2010-10-21 22:46:14 +00001743 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001744 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if (rc != 0)
1746 break;
1747 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001748 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001749 open_file->netfid,
1750 current_read_size, *poffset,
1751 &bytes_read, &smb_read_data,
1752 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001755 if (copy_to_user(current_offset,
1756 smb_read_data +
1757 4 /* RFC1001 length field */ +
1758 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001759 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001760 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001761
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001763 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001764 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001765 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 smb_read_data = NULL;
1767 }
1768 }
1769 if (rc || (bytes_read == 0)) {
1770 if (total_read) {
1771 break;
1772 } else {
1773 FreeXid(xid);
1774 return rc;
1775 }
1776 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001777 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 *poffset += bytes_read;
1779 }
1780 }
1781 FreeXid(xid);
1782 return total_read;
1783}
1784
1785
1786static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1787 loff_t *poffset)
1788{
1789 int rc = -EACCES;
1790 unsigned int bytes_read = 0;
1791 unsigned int total_read;
1792 unsigned int current_read_size;
1793 struct cifs_sb_info *cifs_sb;
1794 struct cifsTconInfo *pTcon;
1795 int xid;
1796 char *current_offset;
1797 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001798 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001801 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301804 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301806 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001808 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001809 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
1811 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001812 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001814 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 read_size > total_read;
1816 total_read += bytes_read, current_offset += bytes_read) {
1817 current_read_size = min_t(const int, read_size - total_read,
1818 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001819 /* For windows me and 9x we do not want to request more
1820 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001822 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1823 current_read_size = min_t(const int, current_read_size,
1824 pTcon->ses->server->maxBuf - 128);
1825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 rc = -EAGAIN;
1827 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001828 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001829 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if (rc != 0)
1831 break;
1832 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001833 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001834 open_file->netfid,
1835 current_read_size, *poffset,
1836 &bytes_read, &current_offset,
1837 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
1839 if (rc || (bytes_read == 0)) {
1840 if (total_read) {
1841 break;
1842 } else {
1843 FreeXid(xid);
1844 return rc;
1845 }
1846 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001847 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 *poffset += bytes_read;
1849 }
1850 }
1851 FreeXid(xid);
1852 return total_read;
1853}
1854
1855int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1856{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 int rc, xid;
1858
1859 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001860 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001862 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 FreeXid(xid);
1864 return rc;
1865 }
1866 rc = generic_file_mmap(file, vma);
1867 FreeXid(xid);
1868 return rc;
1869}
1870
1871
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001873 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874{
1875 struct page *page;
1876 char *target;
1877
1878 while (bytes_read > 0) {
1879 if (list_empty(pages))
1880 break;
1881
1882 page = list_entry(pages->prev, struct page, lru);
1883 list_del(&page->lru);
1884
Nick Piggin315e9952010-04-21 03:18:28 +00001885 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 GFP_KERNEL)) {
1887 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001888 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001889 data += PAGE_CACHE_SIZE;
1890 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 continue;
1892 }
Jeff Layton06b43672010-06-01 10:54:45 -04001893 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001895 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 if (PAGE_CACHE_SIZE > bytes_read) {
1898 memcpy(target, data, bytes_read);
1899 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001900 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 PAGE_CACHE_SIZE - bytes_read);
1902 bytes_read = 0;
1903 } else {
1904 memcpy(target, data, PAGE_CACHE_SIZE);
1905 bytes_read -= PAGE_CACHE_SIZE;
1906 }
1907 kunmap_atomic(target, KM_USER0);
1908
1909 flush_dcache_page(page);
1910 SetPageUptodate(page);
1911 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301913
1914 /* add page to FS-Cache */
1915 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 }
1917 return;
1918}
1919
1920static int cifs_readpages(struct file *file, struct address_space *mapping,
1921 struct list_head *page_list, unsigned num_pages)
1922{
1923 int rc = -EACCES;
1924 int xid;
1925 loff_t offset;
1926 struct page *page;
1927 struct cifs_sb_info *cifs_sb;
1928 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001929 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001930 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 char *smb_read_data = NULL;
1932 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001934 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 xid = GetXid();
1937 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301938 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301940 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001942 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001943 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04001944 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001945
Suresh Jayaraman56698232010-07-05 18:13:25 +05301946 /*
1947 * Reads as many pages as possible from fscache. Returns -ENOBUFS
1948 * immediately if the cookie is negative
1949 */
1950 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
1951 &num_pages);
1952 if (rc == 0)
1953 goto read_complete;
1954
Steve Frenchf19159d2010-04-21 04:12:10 +00001955 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 for (i = 0; i < num_pages; ) {
1957 unsigned contig_pages;
1958 struct page *tmp_page;
1959 unsigned long expected_index;
1960
1961 if (list_empty(page_list))
1962 break;
1963
1964 page = list_entry(page_list->prev, struct page, lru);
1965 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1966
1967 /* count adjacent pages that we will read into */
1968 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001969 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001971 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 if (tmp_page->index == expected_index) {
1973 contig_pages++;
1974 expected_index++;
1975 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 }
1978 if (contig_pages + i > num_pages)
1979 contig_pages = num_pages - i;
1980
1981 /* for reads over a certain size could initiate async
1982 read ahead */
1983
1984 read_size = contig_pages * PAGE_CACHE_SIZE;
1985 /* Read size needs to be in multiples of one page */
1986 read_size = min_t(const unsigned int, read_size,
1987 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001988 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
1989 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 rc = -EAGAIN;
1991 while (rc == -EAGAIN) {
Steve Frenchcdff08e2010-10-21 22:46:14 +00001992 if (open_file->invalidHandle) {
Jeff Layton15886172010-10-15 15:33:59 -04001993 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 if (rc != 0)
1995 break;
1996 }
1997
Steve Frenchbfa0d752005-08-31 21:50:37 -07001998 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001999 open_file->netfid,
2000 read_size, offset,
2001 &bytes_read, &smb_read_data,
2002 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002003 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002004 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002006 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002007 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002008 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002009 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 smb_read_data = NULL;
2011 }
2012 }
2013 }
2014 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002015 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 break;
2017 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002018 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2020 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2021 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002022 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002025 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002026 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 i++; /* account for partial page */
2028
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002029 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002031 /* BB do we need to verify this common case ?
2032 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 we will hit it on next read */
2034
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002035 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002038 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002039 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002040 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002041 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 break;
2044 }
2045 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002047 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002049 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 smb_read_data = NULL;
2051 }
2052 bytes_read = 0;
2053 }
2054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055/* need to free smb_read_data buf before exit */
2056 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002058 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002060 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Suresh Jayaraman56698232010-07-05 18:13:25 +05302064read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 FreeXid(xid);
2066 return rc;
2067}
2068
2069static int cifs_readpage_worker(struct file *file, struct page *page,
2070 loff_t *poffset)
2071{
2072 char *read_data;
2073 int rc;
2074
Suresh Jayaraman56698232010-07-05 18:13:25 +05302075 /* Is the page cached? */
2076 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2077 if (rc == 0)
2078 goto read_complete;
2079
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 page_cache_get(page);
2081 read_data = kmap(page);
2082 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002083
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 if (rc < 0)
2087 goto io_error;
2088 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002089 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002091 file->f_path.dentry->d_inode->i_atime =
2092 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 if (PAGE_CACHE_SIZE > rc)
2095 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2096
2097 flush_dcache_page(page);
2098 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302099
2100 /* send this page to the cache */
2101 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2102
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002104
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002106 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302108
2109read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 return rc;
2111}
2112
2113static int cifs_readpage(struct file *file, struct page *page)
2114{
2115 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2116 int rc = -EACCES;
2117 int xid;
2118
2119 xid = GetXid();
2120
2121 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302122 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302124 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126
Joe Perchesb6b38f72010-04-21 03:50:45 +00002127 cFYI(1, "readpage %p at offset %d 0x%x\n",
2128 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
2130 rc = cifs_readpage_worker(file, page, &offset);
2131
2132 unlock_page(page);
2133
2134 FreeXid(xid);
2135 return rc;
2136}
2137
Steve Frencha403a0a2007-07-26 15:54:16 +00002138static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2139{
2140 struct cifsFileInfo *open_file;
2141
Jeff Layton44772882010-10-15 15:34:03 -04002142 spin_lock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002143 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2e396b82010-10-15 15:34:01 -04002144 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Jeff Layton44772882010-10-15 15:34:03 -04002145 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002146 return 1;
2147 }
2148 }
Jeff Layton44772882010-10-15 15:34:03 -04002149 spin_unlock(&cifs_file_list_lock);
Steve Frencha403a0a2007-07-26 15:54:16 +00002150 return 0;
2151}
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153/* We do not want to update the file size from server for inodes
2154 open for write - to avoid races with writepage extending
2155 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002156 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 but this is tricky to do without racing with writebehind
2158 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002159bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
Steve Frencha403a0a2007-07-26 15:54:16 +00002161 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002162 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002163
Steve Frencha403a0a2007-07-26 15:54:16 +00002164 if (is_inode_writable(cifsInode)) {
2165 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002166 struct cifs_sb_info *cifs_sb;
2167
Steve Frenchc32a0b62006-01-12 14:41:28 -08002168 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002169 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002170 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002171 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002172 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002173 }
2174
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002175 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002176 return true;
Steve French7ba52632007-02-08 18:14:13 +00002177
Steve French4b18f2a2008-04-29 00:06:05 +00002178 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002179 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002180 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181}
2182
Nick Piggind9414772008-09-24 11:32:59 -04002183static int cifs_write_begin(struct file *file, struct address_space *mapping,
2184 loff_t pos, unsigned len, unsigned flags,
2185 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
Nick Piggind9414772008-09-24 11:32:59 -04002187 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2188 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002189 loff_t page_start = pos & PAGE_MASK;
2190 loff_t i_size;
2191 struct page *page;
2192 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002195
Nick Piggin54566b22009-01-04 12:00:53 -08002196 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002197 if (!page) {
2198 rc = -ENOMEM;
2199 goto out;
2200 }
Nick Piggind9414772008-09-24 11:32:59 -04002201
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002202 if (PageUptodate(page))
2203 goto out;
Steve French8a236262007-03-06 00:31:00 +00002204
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002205 /*
2206 * If we write a full page it will be up to date, no need to read from
2207 * the server. If the write is short, we'll end up doing a sync write
2208 * instead.
2209 */
2210 if (len == PAGE_CACHE_SIZE)
2211 goto out;
2212
2213 /*
2214 * optimize away the read when we have an oplock, and we're not
2215 * expecting to use any of the data we'd be reading in. That
2216 * is, when the page lies beyond the EOF, or straddles the EOF
2217 * and the write will cover all of the existing data.
2218 */
2219 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2220 i_size = i_size_read(mapping->host);
2221 if (page_start >= i_size ||
2222 (offset == 0 && (pos + len) >= i_size)) {
2223 zero_user_segments(page, 0, offset,
2224 offset + len,
2225 PAGE_CACHE_SIZE);
2226 /*
2227 * PageChecked means that the parts of the page
2228 * to which we're not writing are considered up
2229 * to date. Once the data is copied to the
2230 * page, it can be set uptodate.
2231 */
2232 SetPageChecked(page);
2233 goto out;
2234 }
2235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Nick Piggind9414772008-09-24 11:32:59 -04002237 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002238 /*
2239 * might as well read a page, it is fast enough. If we get
2240 * an error, we don't need to return it. cifs_write_end will
2241 * do a sync write instead since PG_uptodate isn't set.
2242 */
2243 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002244 } else {
2245 /* we could try using another file handle if there is one -
2246 but how would we lock it to prevent close of that handle
2247 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002248 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002249 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002250out:
2251 *pagep = page;
2252 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253}
2254
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302255static int cifs_release_page(struct page *page, gfp_t gfp)
2256{
2257 if (PagePrivate(page))
2258 return 0;
2259
2260 return cifs_fscache_release_page(page, gfp);
2261}
2262
2263static void cifs_invalidate_page(struct page *page, unsigned long offset)
2264{
2265 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2266
2267 if (offset == 0)
2268 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2269}
2270
Tejun Heo9b646972010-07-20 22:09:02 +02002271void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002272{
2273 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2274 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002275 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002276 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002277 int rc, waitrc = 0;
2278
2279 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002280 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002281 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002282 else
Al Viro8737c932009-12-24 06:47:55 -05002283 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002284 rc = filemap_fdatawrite(inode->i_mapping);
2285 if (cinode->clientCanCacheRead == 0) {
2286 waitrc = filemap_fdatawait(inode->i_mapping);
2287 invalidate_remote_inode(inode);
2288 }
2289 if (!rc)
2290 rc = waitrc;
2291 if (rc)
2292 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002293 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002294 }
2295
2296 /*
2297 * releasing stale oplock after recent reconnect of smb session using
2298 * a now incorrect file handle is not a data integrity issue but do
2299 * not bother sending an oplock release if session to server still is
2300 * disconnected since oplock already released by the server
2301 */
Steve Frenchcdff08e2010-10-21 22:46:14 +00002302 if (!cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002303 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2304 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002305 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002306 }
Tejun Heo9b646972010-07-20 22:09:02 +02002307
2308 /*
2309 * We might have kicked in before is_valid_oplock_break()
2310 * finished grabbing reference for us. Make sure it's done by
2311 * waiting for GlobalSMSSeslock.
2312 */
Jeff Layton44772882010-10-15 15:34:03 -04002313 spin_lock(&cifs_file_list_lock);
2314 spin_unlock(&cifs_file_list_lock);
Tejun Heo9b646972010-07-20 22:09:02 +02002315
2316 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002317}
2318
Jeff Layton5f6dbc92010-10-15 15:34:06 -04002319/* must be called while holding cifs_file_list_lock */
Tejun Heo9b646972010-07-20 22:09:02 +02002320void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002321{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002322 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002323 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002324}
2325
Tejun Heo9b646972010-07-20 22:09:02 +02002326void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002327{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002328 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002329 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002330}
2331
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002332const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 .readpage = cifs_readpage,
2334 .readpages = cifs_readpages,
2335 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002336 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002337 .write_begin = cifs_write_begin,
2338 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302340 .releasepage = cifs_release_page,
2341 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 /* .sync_page = cifs_sync_page, */
2343 /* .direct_IO = */
2344};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002345
2346/*
2347 * cifs_readpages requires the server to support a buffer large enough to
2348 * contain the header plus one complete page of data. Otherwise, we need
2349 * to leave cifs_readpages out of the address space operations.
2350 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002351const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002352 .readpage = cifs_readpage,
2353 .writepage = cifs_writepage,
2354 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002355 .write_begin = cifs_write_begin,
2356 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002357 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302358 .releasepage = cifs_release_page,
2359 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002360 /* .sync_page = cifs_sync_page, */
2361 /* .direct_IO = */
2362};