blob: 293e9b76762179c98656f9e3ef18385c31e5d6e3 [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
235 pCifsFile->netfid = fileHandle;
236 pCifsFile->pid = current->tgid;
237 pCifsFile->uid = current_fsuid();
238 pCifsFile->dentry = dget(dentry);
239 pCifsFile->f_flags = file->f_flags;
240 pCifsFile->invalidHandle = false;
241 pCifsFile->closePend = false;
242 pCifsFile->tlink = cifs_get_tlink(tlink);
243 mutex_init(&pCifsFile->fh_mutex);
244 mutex_init(&pCifsFile->lock_mutex);
245 INIT_LIST_HEAD(&pCifsFile->llist);
246 atomic_set(&pCifsFile->count, 1);
247 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
248
249 write_lock(&GlobalSMBSeslock);
250 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
251 /* if readable file instance put first in list*/
252 if (file->f_mode & FMODE_READ)
253 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
254 else
255 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
256 write_unlock(&GlobalSMBSeslock);
257
258 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
259 pCifsInode->clientCanCacheAll = true;
260 pCifsInode->clientCanCacheRead = true;
261 cFYI(1, "Exclusive Oplock inode %p", inode);
262 } else if ((oplock & 0xF) == OPLOCK_READ)
263 pCifsInode->clientCanCacheRead = true;
264
265 file->private_data = pCifsFile;
266 return pCifsFile;
267}
268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269int cifs_open(struct inode *inode, struct file *file)
270{
271 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400272 int xid;
273 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000275 struct cifsTconInfo *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400276 struct tcon_link *tlink;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400277 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 char *full_path = NULL;
280 int desiredAccess;
281 int disposition;
282 __u16 netfid;
283 FILE_ALL_INFO *buf = NULL;
284
285 xid = GetXid();
286
287 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400288 tlink = cifs_sb_tlink(cifs_sb);
289 if (IS_ERR(tlink)) {
290 FreeXid(xid);
291 return PTR_ERR(tlink);
292 }
293 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Steve Frencha6ce4932009-04-09 01:14:32 +0000295 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800297 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530299 rc = -ENOMEM;
Jeff Layton232341b2010-08-05 13:58:38 -0400300 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
Joe Perchesb6b38f72010-04-21 03:50:45 +0000303 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
304 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000305
306 if (oplockEnabled)
307 oplock = REQ_OPLOCK;
308 else
309 oplock = 0;
310
Steve French64cc2c62009-03-04 19:54:08 +0000311 if (!tcon->broken_posix_open && tcon->unix_ext &&
312 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000313 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
314 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French276a74a2009-03-03 18:00:34 +0000315 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400316 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000317 cifs_sb->mnt_file_mode /* ignored */,
Jeff Layton608712f2010-10-15 15:33:56 -0400318 file->f_flags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000319 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000320 cFYI(1, "posix open succeeded");
Jeff Layton47c78b72010-06-16 13:40:17 -0400321
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400322 pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
323 oplock);
Jeff Layton2422f672010-06-16 13:40:16 -0400324 if (pCifsFile == NULL) {
325 CIFSSMBClose(xid, tcon, netfid);
326 rc = -ENOMEM;
Jeff Layton2422f672010-06-16 13:40:16 -0400327 }
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530328
329 cifs_fscache_set_inode_cookie(inode, file);
330
Steve French276a74a2009-03-03 18:00:34 +0000331 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000332 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
333 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000334 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000335 " unexpected error on SMB posix open"
336 ", disabling posix open support."
337 " Check if server update available.",
338 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000339 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000340 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000341 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
342 (rc != -EOPNOTSUPP)) /* path not found or net err */
343 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000344 /* else fallthrough to retry open the old way on network i/o
345 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000346 }
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 desiredAccess = cifs_convert_flags(file->f_flags);
349
350/*********************************************************************
351 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000352 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000354 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 * O_CREAT FILE_OPEN_IF
356 * O_CREAT | O_EXCL FILE_CREATE
357 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
358 * O_TRUNC FILE_OVERWRITE
359 * none of the above FILE_OPEN
360 *
361 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000362 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 * O_CREAT | O_TRUNC is similar but truncates the existing
364 * file rather than creating a new file as FILE_SUPERSEDE does
365 * (which uses the attributes / metadata passed in on open call)
366 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000367 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 *? and the read write flags match reasonably. O_LARGEFILE
369 *? is irrelevant because largefile support is always used
370 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
371 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
372 *********************************************************************/
373
374 disposition = cifs_get_disposition(file->f_flags);
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 /* BB pass O_SYNC flag through on file attributes .. BB */
377
378 /* Also refresh inode by passing in file_info buf returned by SMBOpen
379 and calling get_inode_info with returned buf (at least helps
380 non-Unix server case) */
381
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000382 /* BB we can not do this if this is the second open of a file
383 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
385 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
386 if (!buf) {
387 rc = -ENOMEM;
388 goto out;
389 }
Steve French5bafd762006-06-07 00:18:43 +0000390
Jeff Laytona6e8a842010-09-20 16:01:33 -0700391 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000392 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000393 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700394 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
395 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000396 else
397 rc = -EIO; /* no NT SMB support fall into legacy open below */
398
Steve Frencha9d02ad2005-08-24 23:06:05 -0700399 if (rc == -EIO) {
400 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000401 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700402 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
403 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
404 & CIFS_MOUNT_MAP_SPECIAL_CHR);
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 goto out;
409 }
Jeff Layton3321b792009-09-25 09:53:37 -0400410
Suresh Jayaramana347ecb2010-09-17 19:43:10 +0530411 rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
Jeff Layton47c78b72010-06-16 13:40:17 -0400412 if (rc != 0)
413 goto out;
414
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400415 pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400416 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 rc = -ENOMEM;
418 goto out;
419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530421 cifs_fscache_set_inode_cookie(inode, file);
422
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000423 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 /* time to set mode which we can not set earlier due to
425 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000426 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400427 struct cifs_unix_set_info_args args = {
428 .mode = inode->i_mode,
429 .uid = NO_CHANGE_64,
430 .gid = NO_CHANGE_64,
431 .ctime = NO_CHANGE_64,
432 .atime = NO_CHANGE_64,
433 .mtime = NO_CHANGE_64,
434 .device = 0,
435 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400436 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
437 cifs_sb->local_nls,
438 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700439 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
441 }
442
443out:
444 kfree(buf);
445 kfree(full_path);
446 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400447 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return rc;
449}
450
Adrian Bunk04187262006-06-30 18:23:04 +0200451/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452/* to server was lost */
453static int cifs_relock_file(struct cifsFileInfo *cifsFile)
454{
455 int rc = 0;
456
457/* BB list all locks open on this file and relock */
458
459 return rc;
460}
461
Jeff Layton15886172010-10-15 15:33:59 -0400462static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
464 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400465 int xid;
466 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000468 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 char *full_path = NULL;
472 int desiredAccess;
473 int disposition = FILE_OPEN;
474 __u16 netfid;
475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400477 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000478 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400479 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530480 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530482 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484
Jeff Layton15886172010-10-15 15:33:59 -0400485 inode = pCifsFile->dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400487 tcon = tlink_tcon(pCifsFile->tlink);
Steve French3a9f4622007-04-04 17:10:24 +0000488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489/* can not grab rename sem here because various ops, including
490 those that already have the rename sem can end up causing writepage
491 to get called and if the server was down that means we end up here,
492 and we can never tell if the caller already has the rename_sem */
Jeff Layton15886172010-10-15 15:33:59 -0400493 full_path = build_path_from_dentry(pCifsFile->dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000495 rc = -ENOMEM;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400496 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000498 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
Jeff Layton15886172010-10-15 15:33:59 -0400502 inode, pCifsFile->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 if (oplockEnabled)
505 oplock = REQ_OPLOCK;
506 else
Steve French4b18f2a2008-04-29 00:06:05 +0000507 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Steve French7fc8f4e2009-02-23 20:43:11 +0000509 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
510 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
511 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton608712f2010-10-15 15:33:56 -0400512
513 /*
514 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
515 * original open. Must mask them off for a reopen.
516 */
Jeff Layton15886172010-10-15 15:33:59 -0400517 unsigned int oflags = pCifsFile->f_flags &
518 ~(O_CREAT | O_EXCL | O_TRUNC);
Jeff Layton608712f2010-10-15 15:33:56 -0400519
Jeff Layton2422f672010-06-16 13:40:16 -0400520 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000521 cifs_sb->mnt_file_mode /* ignored */,
522 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000523 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000524 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000525 goto reopen_success;
526 }
527 /* fallthrough to retry open the old way on errors, especially
528 in the reconnect path it is important to retry hard */
529 }
530
Jeff Layton15886172010-10-15 15:33:59 -0400531 desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
Steve French7fc8f4e2009-02-23 20:43:11 +0000532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 by SMBOpen and then calling get_inode_info with returned buf
535 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 and server version of file size can be stale. If we knew for sure
537 that inode was not dirty locally we could do this */
538
Steve French7fc8f4e2009-02-23 20:43:11 +0000539 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700542 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400544 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000545 cFYI(1, "cifs_open returned 0x%x", rc);
546 cFYI(1, "oplock: %d", oplock);
Jeff Layton15886172010-10-15 15:33:59 -0400547 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
Jeff Layton15886172010-10-15 15:33:59 -0400549
550reopen_success:
551 pCifsFile->netfid = netfid;
552 pCifsFile->invalidHandle = false;
553 mutex_unlock(&pCifsFile->fh_mutex);
554 pCifsInode = CIFS_I(inode);
555
556 if (can_flush) {
557 rc = filemap_write_and_wait(inode->i_mapping);
558 if (rc != 0)
559 CIFS_I(inode)->write_behind_rc = rc;
560
561 pCifsInode->clientCanCacheAll = false;
562 pCifsInode->clientCanCacheRead = false;
563 if (tcon->unix_ext)
564 rc = cifs_get_inode_info_unix(&inode,
565 full_path, inode->i_sb, xid);
566 else
567 rc = cifs_get_inode_info(&inode,
568 full_path, NULL, inode->i_sb,
569 xid, NULL);
570 } /* else we are writing out data to server already
571 and could deadlock if we tried to flush data, and
572 since we do not know if we have data that would
573 invalidate the current end of file on the server
574 we can not go to the server to get the new inod
575 info */
576 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
577 pCifsInode->clientCanCacheAll = true;
578 pCifsInode->clientCanCacheRead = true;
579 cFYI(1, "Exclusive Oplock granted on inode %p",
580 pCifsFile->dentry->d_inode);
581 } else if ((oplock & 0xF) == OPLOCK_READ) {
582 pCifsInode->clientCanCacheRead = true;
583 pCifsInode->clientCanCacheAll = false;
584 } else {
585 pCifsInode->clientCanCacheRead = false;
586 pCifsInode->clientCanCacheAll = false;
587 }
588 cifs_relock_file(pCifsFile);
589
590reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 kfree(full_path);
592 FreeXid(xid);
593 return rc;
594}
595
596int cifs_close(struct inode *inode, struct file *file)
597{
598 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000599 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 struct cifs_sb_info *cifs_sb;
601 struct cifsTconInfo *pTcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700602 struct cifsFileInfo *pSMBFile = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 xid = GetXid();
605
606 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400607 pTcon = tlink_tcon(pSMBFile->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000609 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000610 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000611 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (pTcon) {
613 /* no sense reconnecting to close a file that is
614 already closed */
Steve French3b795212008-11-13 19:45:32 +0000615 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000616 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000617 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400618 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000619 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700620 /* Give write a better chance to get to
621 server ahead of the close. We do not
622 want to add a wait_q here as it would
623 increase the memory utilization as
624 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000625 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700626 clear the socket */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cFYI(DBG2, "close delay, write pending");
Steve French23e7dd72005-10-20 13:44:56 -0700628 msleep(timeout);
629 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000630 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000631 if (!pTcon->need_reconnect &&
632 !pSMBFile->invalidHandle)
633 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000635 } else
636 write_unlock(&GlobalSMBSeslock);
637 } else
638 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000639
640 /* Delete any outstanding lock records.
641 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000642 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000643 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
644 list_del(&li->llist);
645 kfree(li);
646 }
Roland Dreier796e5662007-05-03 04:33:45 +0000647 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000648
Steve Frenchcbe04762005-04-28 22:41:05 -0700649 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 list_del(&pSMBFile->flist);
651 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700652 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400653 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 file->private_data = NULL;
655 } else
656 rc = -EBADF;
657
Steve French4efa53f2007-09-11 05:50:53 +0000658 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 if (list_empty(&(CIFS_I(inode)->openFileList))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000660 cFYI(1, "closing last open instance for inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /* if the file is not open we do not know if we can cache info
662 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000663 CIFS_I(inode)->clientCanCacheRead = false;
664 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
Steve French4efa53f2007-09-11 05:50:53 +0000666 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000667 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 rc = CIFS_I(inode)->write_behind_rc;
669 FreeXid(xid);
670 return rc;
671}
672
673int cifs_closedir(struct inode *inode, struct file *file)
674{
675 int rc = 0;
676 int xid;
Joe Perchesc21dfb62010-07-12 13:50:14 -0700677 struct cifsFileInfo *pCFileStruct = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 char *ptmp;
679
Joe Perchesb6b38f72010-04-21 03:50:45 +0000680 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 xid = GetXid();
683
684 if (pCFileStruct) {
Jeff Layton13cfb732010-09-29 19:51:11 -0400685 struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Joe Perchesb6b38f72010-04-21 03:50:45 +0000687 cFYI(1, "Freeing private data in close dir");
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000688 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000689 if (!pCFileStruct->srch_inf.endOfSearch &&
690 !pCFileStruct->invalidHandle) {
691 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000692 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000694 cFYI(1, "Closing uncompleted readdir with rc %d",
695 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 /* not much we can do if it fails anyway, ignore rc */
697 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000698 } else
699 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
701 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000704 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000705 cifs_small_buf_release(ptmp);
706 else
707 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Jeff Layton13cfb732010-09-29 19:51:11 -0400709 cifs_put_tlink(pCFileStruct->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 kfree(file->private_data);
711 file->private_data = NULL;
712 }
713 /* BB can we lock the filestruct while this is going on? */
714 FreeXid(xid);
715 return rc;
716}
717
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000718static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
719 __u64 offset, __u8 lockType)
720{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000721 struct cifsLockInfo *li =
722 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000723 if (li == NULL)
724 return -ENOMEM;
725 li->offset = offset;
726 li->length = len;
727 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000728 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000729 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000730 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000731 return 0;
732}
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
735{
736 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 __u32 numLock = 0;
738 __u32 numUnlock = 0;
739 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000740 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000742 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000743 __u16 netfid;
744 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000745 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 length = 1 + pfLock->fl_end - pfLock->fl_start;
748 rc = -EACCES;
749 xid = GetXid();
750
Joe Perchesb6b38f72010-04-21 03:50:45 +0000751 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000753 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000762 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
764 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000765 cFYI(1, "Process suspended by mandatory locking - "
766 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000768 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000769 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000771 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000774 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 numLock = 1;
776 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000777 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000779 /* Check if unlock includes more than
780 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000782 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 lockType |= LOCKING_ANDX_SHARED_LOCK;
784 numLock = 1;
785 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000786 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 numLock = 1;
788 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000789 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 lockType |= LOCKING_ANDX_SHARED_LOCK;
791 numLock = 1;
792 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000793 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800795 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -0400796 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530799 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530801 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 }
Steve French08547b02006-02-28 22:39:25 +0000803 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Steve French13a6e422008-12-02 17:24:33 +0000805 if ((tcon->ses->capabilities & CAP_UNIX) &&
806 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000807 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000808 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000809 /* BB add code here to normalize offset and length to
810 account for negative length which we can not accept over the
811 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000813 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000814 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000815 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000816 posix_lock_type = CIFS_RDLCK;
817 else
818 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000819 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000820 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000821 posix_lock_type, wait_flag);
822 FreeXid(xid);
823 return rc;
824 }
825
826 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000827 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000828 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000830 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 pfLock->fl_start, 1 /* numUnlock */ ,
832 0 /* numLock */ , lockType,
833 0 /* wait flag */ );
834 pfLock->fl_type = F_UNLCK;
835 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000836 cERROR(1, "Error unlocking previously locked "
837 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 rc = 0;
839
840 } else {
841 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400842 rc = 0;
843
844 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
845 pfLock->fl_type = F_WRLCK;
846 } else {
847 rc = CIFSSMBLock(xid, tcon, netfid, length,
848 pfLock->fl_start, 0, 1,
849 lockType | LOCKING_ANDX_SHARED_LOCK,
850 0 /* wait flag */);
851 if (rc == 0) {
852 rc = CIFSSMBLock(xid, tcon, netfid,
853 length, pfLock->fl_start, 1, 0,
854 lockType |
855 LOCKING_ANDX_SHARED_LOCK,
856 0 /* wait flag */);
857 pfLock->fl_type = F_RDLCK;
858 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000859 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400860 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000861 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400862 rc = 0;
863 } else {
864 pfLock->fl_type = F_WRLCK;
865 rc = 0;
866 }
867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869
870 FreeXid(xid);
871 return rc;
872 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000873
874 if (!numLock && !numUnlock) {
875 /* if no lock or unlock then nothing
876 to do since we do not know what it is */
877 FreeXid(xid);
878 return -EOPNOTSUPP;
879 }
880
881 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000882 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000883 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000884 posix_lock_type = CIFS_RDLCK;
885 else
886 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000887
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000889 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890
Steve French13a6e422008-12-02 17:24:33 +0000891 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000892 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000893 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000894 } else {
Joe Perchesc21dfb62010-07-12 13:50:14 -0700895 struct cifsFileInfo *fid = file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896
897 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000898 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000900 0, numLock, lockType, wait_flag);
901
902 if (rc == 0) {
903 /* For Windows locks we must store them. */
904 rc = store_file_lock(fid, length,
905 pfLock->fl_start, lockType);
906 }
907 } else if (numUnlock) {
908 /* For each stored lock that this unlock overlaps
909 completely, unlock it. */
910 int stored_rc = 0;
911 struct cifsLockInfo *li, *tmp;
912
Steve French6b70c952006-09-21 07:35:29 +0000913 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000914 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
916 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000917 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000918 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000919 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000920 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000921 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000922 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000923 if (stored_rc)
924 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000925 else {
926 list_del(&li->llist);
927 kfree(li);
928 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000929 }
930 }
Roland Dreier796e5662007-05-03 04:33:45 +0000931 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 }
933 }
934
Steve Frenchd634cc12005-08-26 14:42:59 -0500935 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 posix_lock_file_wait(file, pfLock);
937 FreeXid(xid);
938 return rc;
939}
940
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400941/*
942 * Set the timeout on write requests past EOF. For some servers (Windows)
943 * these calls can be very long.
944 *
945 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
946 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
947 * The 10M cutoff is totally arbitrary. A better scheme for this would be
948 * welcome if someone wants to suggest one.
949 *
950 * We may be able to do a better job with this if there were some way to
951 * declare that a file should be sparse.
952 */
953static int
954cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
955{
956 if (offset <= cifsi->server_eof)
957 return CIFS_STD_OP;
958 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
959 return CIFS_VLONG_OP;
960 else
961 return CIFS_LONG_OP;
962}
963
964/* update the file size (if needed) after a write */
965static void
966cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
967 unsigned int bytes_written)
968{
969 loff_t end_of_write = offset + bytes_written;
970
971 if (end_of_write > cifsi->server_eof)
972 cifsi->server_eof = end_of_write;
973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975ssize_t cifs_user_write(struct file *file, const char __user *write_data,
976 size_t write_size, loff_t *poffset)
977{
978 int rc = 0;
979 unsigned int bytes_written = 0;
980 unsigned int total_written;
981 struct cifs_sb_info *cifs_sb;
982 struct cifsTconInfo *pTcon;
983 int xid, long_op;
984 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400985 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800987 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Joe Perchesb6b38f72010-04-21 03:50:45 +0000989 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
990 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 if (file->private_data == NULL)
993 return -EBADF;
Jeff Laytonba00ba62010-09-20 16:01:31 -0700994
Joe Perchesc21dfb62010-07-12 13:50:14 -0700995 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -0400996 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +0000997
Jeff Layton838726c2008-08-28 07:54:59 -0400998 rc = generic_write_checks(file, poffset, &write_size, 0);
999 if (rc)
1000 return rc;
1001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001004 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 for (total_written = 0; write_size > total_written;
1006 total_written += bytes_written) {
1007 rc = -EAGAIN;
1008 while (rc == -EAGAIN) {
1009 if (file->private_data == NULL) {
1010 /* file has been closed on us */
1011 FreeXid(xid);
1012 /* if we have gotten here we have written some data
1013 and blocked, and the file has been freed on us while
1014 we blocked so return what we managed to write */
1015 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (open_file->closePend) {
1018 FreeXid(xid);
1019 if (total_written)
1020 return total_written;
1021 else
1022 return -EBADF;
1023 }
1024 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 /* we could deadlock if we called
1026 filemap_fdatawait from here so tell
1027 reopen_file not to flush data to server
1028 now */
Jeff Layton15886172010-10-15 15:33:59 -04001029 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (rc != 0)
1031 break;
1032 }
1033
1034 rc = CIFSSMBWrite(xid, pTcon,
1035 open_file->netfid,
1036 min_t(const int, cifs_sb->wsize,
1037 write_size - total_written),
1038 *poffset, &bytes_written,
1039 NULL, write_data + total_written, long_op);
1040 }
1041 if (rc || (bytes_written == 0)) {
1042 if (total_written)
1043 break;
1044 else {
1045 FreeXid(xid);
1046 return rc;
1047 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001048 } else {
1049 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001051 }
Steve French133672e2007-11-13 22:41:37 +00001052 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 15 seconds is plenty */
1054 }
1055
Steve Frencha4544342005-08-24 13:59:35 -07001056 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001059 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1060 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001061/* Do not update local mtime - server will set its actual value on write
1062 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001063 * current_fs_time(inode->i_sb);*/
1064 if (total_written > 0) {
1065 spin_lock(&inode->i_lock);
1066 if (*poffset > file->f_path.dentry->d_inode->i_size)
1067 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001069 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001071 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073 FreeXid(xid);
1074 return total_written;
1075}
1076
Jeff Layton7da4b492010-10-15 15:34:00 -04001077static ssize_t cifs_write(struct cifsFileInfo *open_file,
1078 const char *write_data, size_t write_size,
1079 loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
1081 int rc = 0;
1082 unsigned int bytes_written = 0;
1083 unsigned int total_written;
1084 struct cifs_sb_info *cifs_sb;
1085 struct cifsTconInfo *pTcon;
1086 int xid, long_op;
Jeff Layton7da4b492010-10-15 15:34:00 -04001087 struct dentry *dentry = open_file->dentry;
1088 struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Jeff Layton7da4b492010-10-15 15:34:00 -04001090 cifs_sb = CIFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Joe Perchesb6b38f72010-04-21 03:50:45 +00001092 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
Jeff Layton7da4b492010-10-15 15:34:00 -04001093 *poffset, dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Jeff Layton13cfb732010-09-29 19:51:11 -04001095 pTcon = tlink_tcon(open_file->tlink);
Steve French50c2f752007-07-13 00:33:32 +00001096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001099 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 for (total_written = 0; write_size > total_written;
1101 total_written += bytes_written) {
1102 rc = -EAGAIN;
1103 while (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (open_file->closePend) {
1105 FreeXid(xid);
1106 if (total_written)
1107 return total_written;
1108 else
1109 return -EBADF;
1110 }
1111 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 /* we could deadlock if we called
1113 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001114 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 server now */
Jeff Layton15886172010-10-15 15:33:59 -04001116 rc = cifs_reopen_file(open_file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (rc != 0)
1118 break;
1119 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001120 if (experimEnabled || (pTcon->ses->server &&
1121 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001122 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001123 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001124 struct kvec iov[2];
1125 unsigned int len;
1126
Steve French0ae0efa2005-10-10 10:57:19 -07001127 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001128 write_size - total_written);
1129 /* iov[0] is reserved for smb header */
1130 iov[1].iov_base = (char *)write_data +
1131 total_written;
1132 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001133 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001134 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001135 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001136 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001137 } else
Steve French60808232006-04-22 15:53:05 +00001138 rc = CIFSSMBWrite(xid, pTcon,
1139 open_file->netfid,
1140 min_t(const int, cifs_sb->wsize,
1141 write_size - total_written),
1142 *poffset, &bytes_written,
1143 write_data + total_written,
1144 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146 if (rc || (bytes_written == 0)) {
1147 if (total_written)
1148 break;
1149 else {
1150 FreeXid(xid);
1151 return rc;
1152 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001153 } else {
1154 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001156 }
Steve French133672e2007-11-13 22:41:37 +00001157 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 15 seconds is plenty */
1159 }
1160
Steve Frencha4544342005-08-24 13:59:35 -07001161 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jeff Layton7da4b492010-10-15 15:34:00 -04001163 if (total_written > 0) {
1164 spin_lock(&dentry->d_inode->i_lock);
1165 if (*poffset > dentry->d_inode->i_size)
1166 i_size_write(dentry->d_inode, *poffset);
1167 spin_unlock(&dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
Jeff Layton7da4b492010-10-15 15:34:00 -04001169 mark_inode_dirty_sync(dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 FreeXid(xid);
1171 return total_written;
1172}
1173
Steve French630f3f0c2007-10-25 21:17:17 +00001174#ifdef CONFIG_CIFS_EXPERIMENTAL
Jeff Layton6508d902010-09-29 19:51:11 -04001175struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1176 bool fsuid_only)
Steve French630f3f0c2007-10-25 21:17:17 +00001177{
1178 struct cifsFileInfo *open_file = NULL;
Jeff Layton6508d902010-09-29 19:51:11 -04001179 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1180
1181 /* only filter by fsuid on multiuser mounts */
1182 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1183 fsuid_only = false;
Steve French630f3f0c2007-10-25 21:17:17 +00001184
1185 read_lock(&GlobalSMBSeslock);
1186 /* we could simply get the first_list_entry since write-only entries
1187 are always at the end of the list but since the first entry might
1188 have a close pending, we go through the whole list */
1189 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1190 if (open_file->closePend)
1191 continue;
Jeff Layton6508d902010-09-29 19:51:11 -04001192 if (fsuid_only && open_file->uid != current_fsuid())
1193 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001194 if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
Steve French630f3f0c2007-10-25 21:17:17 +00001195 if (!open_file->invalidHandle) {
1196 /* found a good file */
1197 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001198 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001199 read_unlock(&GlobalSMBSeslock);
1200 return open_file;
1201 } /* else might as well continue, and look for
1202 another, or simply have the caller reopen it
1203 again rather than trying to fix this handle */
1204 } else /* write only file */
1205 break; /* write only files are last so must be done */
1206 }
1207 read_unlock(&GlobalSMBSeslock);
1208 return NULL;
1209}
1210#endif
1211
Jeff Layton6508d902010-09-29 19:51:11 -04001212struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1213 bool fsuid_only)
Steve French6148a742005-10-05 12:23:19 -07001214{
1215 struct cifsFileInfo *open_file;
Jeff Layton6508d902010-09-29 19:51:11 -04001216 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
Jeff Layton2846d382008-09-22 21:33:33 -04001217 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001218 int rc;
Steve French6148a742005-10-05 12:23:19 -07001219
Steve French60808232006-04-22 15:53:05 +00001220 /* Having a null inode here (because mapping->host was set to zero by
1221 the VFS or MM) should not happen but we had reports of on oops (due to
1222 it being zero) during stress testcases so we need to check for it */
1223
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001224 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001225 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001226 dump_stack();
1227 return NULL;
1228 }
1229
Jeff Layton6508d902010-09-29 19:51:11 -04001230 /* only filter by fsuid on multiuser mounts */
1231 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1232 fsuid_only = false;
1233
Steve French6148a742005-10-05 12:23:19 -07001234 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001235refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001236 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton6508d902010-09-29 19:51:11 -04001237 if (open_file->closePend)
Steve French6148a742005-10-05 12:23:19 -07001238 continue;
Jeff Layton6508d902010-09-29 19:51:11 -04001239 if (!any_available && open_file->pid != current->tgid)
1240 continue;
1241 if (fsuid_only && open_file->uid != current_fsuid())
1242 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04001243 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001244 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001245
1246 if (!open_file->invalidHandle) {
1247 /* found a good writable file */
1248 read_unlock(&GlobalSMBSeslock);
1249 return open_file;
1250 }
Steve French8840dee2007-11-16 23:05:52 +00001251
Steve French6148a742005-10-05 12:23:19 -07001252 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001253 /* Had to unlock since following call can block */
Jeff Layton15886172010-10-15 15:33:59 -04001254 rc = cifs_reopen_file(open_file, false);
Steve French8840dee2007-11-16 23:05:52 +00001255 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001256 if (!open_file->closePend)
1257 return open_file;
1258 else { /* start over in case this was deleted */
1259 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001260 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001261 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001262 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001263 }
1264 }
Steve French9b22b0b2007-10-02 01:11:08 +00001265
1266 /* if it fails, try another handle if possible -
1267 (we can not do this if closePending since
1268 loop could be modified - in which case we
1269 have to start at the beginning of the list
1270 again. Note that it would be bad
1271 to hold up writepages here (rather than
1272 in caller) with continuous retries */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001273 cFYI(1, "wp failed on reopen file");
Steve French9b22b0b2007-10-02 01:11:08 +00001274 read_lock(&GlobalSMBSeslock);
1275 /* can not use this handle, no write
1276 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001277 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001278
Steve French9b22b0b2007-10-02 01:11:08 +00001279 if (open_file->closePend) /* list could have changed */
1280 goto refind_writable;
1281 /* else we simply continue to the next entry. Thus
1282 we do not loop on reopen errors. If we
1283 can not reopen the file, for example if we
1284 reconnected to a server with another client
1285 racing to delete or lock the file we would not
1286 make progress if we restarted before the beginning
1287 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001288 }
1289 }
Jeff Layton2846d382008-09-22 21:33:33 -04001290 /* couldn't find useable FH with same pid, try any available */
1291 if (!any_available) {
1292 any_available = true;
1293 goto refind_writable;
1294 }
Steve French6148a742005-10-05 12:23:19 -07001295 read_unlock(&GlobalSMBSeslock);
1296 return NULL;
1297}
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1300{
1301 struct address_space *mapping = page->mapping;
1302 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1303 char *write_data;
1304 int rc = -EFAULT;
1305 int bytes_written = 0;
1306 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001308 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
1310 if (!mapping || !mapping->host)
1311 return -EFAULT;
1312
1313 inode = page->mapping->host;
1314 cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316 offset += (loff_t)from;
1317 write_data = kmap(page);
1318 write_data += from;
1319
1320 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1321 kunmap(page);
1322 return -EIO;
1323 }
1324
1325 /* racing with truncate? */
1326 if (offset > mapping->host->i_size) {
1327 kunmap(page);
1328 return 0; /* don't care */
1329 }
1330
1331 /* check to make sure that we are not extending the file */
1332 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001333 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Jeff Layton6508d902010-09-29 19:51:11 -04001335 open_file = find_writable_file(CIFS_I(mapping->host), false);
Steve French6148a742005-10-05 12:23:19 -07001336 if (open_file) {
Jeff Layton7da4b492010-10-15 15:34:00 -04001337 bytes_written = cifs_write(open_file, write_data,
1338 to - from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001339 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001341 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001342 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001343 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001344 else if (bytes_written < 0)
1345 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001346 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001347 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 rc = -EIO;
1349 }
1350
1351 kunmap(page);
1352 return rc;
1353}
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001356 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
Steve French37c0eb42005-10-05 14:50:29 -07001358 struct backing_dev_info *bdi = mapping->backing_dev_info;
1359 unsigned int bytes_to_write;
1360 unsigned int bytes_written;
1361 struct cifs_sb_info *cifs_sb;
1362 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001363 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001364 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001365 int range_whole = 0;
1366 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001367 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001368 int n_iov = 0;
1369 pgoff_t next;
1370 int nr_pages;
1371 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001372 struct cifsFileInfo *open_file;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001373 struct cifsTconInfo *tcon;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001374 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001375 struct page *page;
1376 struct pagevec pvec;
1377 int rc = 0;
1378 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001379 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Jeff Laytonf3983c22010-09-22 16:17:40 -07001381 /*
1382 * BB: Is this meaningful for a non-block-device file system?
1383 * If it is, we should test it again after we do I/O
1384 */
1385 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1386 wbc->encountered_congestion = 1;
1387 return 0;
1388 }
1389
Steve French37c0eb42005-10-05 14:50:29 -07001390 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001391
Steve French37c0eb42005-10-05 14:50:29 -07001392 /*
1393 * If wsize is smaller that the page cache size, default to writing
1394 * one page at a time via cifs_writepage
1395 */
1396 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1397 return generic_writepages(mapping, wbc);
1398
Steve French9a0c8232007-02-02 04:21:57 +00001399 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001400 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001401 return generic_writepages(mapping, wbc);
1402
Steve French37c0eb42005-10-05 14:50:29 -07001403 /*
Jeff Laytonf3983c22010-09-22 16:17:40 -07001404 * if there's no open file, then this is likely to fail too,
1405 * but it'll at least handle the return. Maybe it should be
1406 * a BUG() instead?
Steve French37c0eb42005-10-05 14:50:29 -07001407 */
Jeff Layton6508d902010-09-29 19:51:11 -04001408 open_file = find_writable_file(CIFS_I(mapping->host), false);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001409 if (!open_file) {
Steve French9a0c8232007-02-02 04:21:57 +00001410 kfree(iov);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001411 return generic_writepages(mapping, wbc);
Steve French37c0eb42005-10-05 14:50:29 -07001412 }
1413
Jeff Layton13cfb732010-09-29 19:51:11 -04001414 tcon = tlink_tcon(open_file->tlink);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001415 if (!experimEnabled && tcon->ses->server->secMode &
1416 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1417 cifsFileInfo_put(open_file);
1418 return generic_writepages(mapping, wbc);
1419 }
1420 cifsFileInfo_put(open_file);
1421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 xid = GetXid();
1423
Steve French37c0eb42005-10-05 14:50:29 -07001424 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001425 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001426 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001427 end = -1;
1428 } else {
1429 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1430 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1431 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1432 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001433 scanned = 1;
1434 }
1435retry:
1436 while (!done && (index <= end) &&
1437 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1438 PAGECACHE_TAG_DIRTY,
1439 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1440 int first;
1441 unsigned int i;
1442
Steve French37c0eb42005-10-05 14:50:29 -07001443 first = -1;
1444 next = 0;
1445 n_iov = 0;
1446 bytes_to_write = 0;
1447
1448 for (i = 0; i < nr_pages; i++) {
1449 page = pvec.pages[i];
1450 /*
1451 * At this point we hold neither mapping->tree_lock nor
1452 * lock on the page itself: the page may be truncated or
1453 * invalidated (changing page->mapping to NULL), or even
1454 * swizzled back from swapper_space to tmpfs file
1455 * mapping
1456 */
1457
1458 if (first < 0)
1459 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001460 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001461 break;
1462
1463 if (unlikely(page->mapping != mapping)) {
1464 unlock_page(page);
1465 break;
1466 }
1467
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001468 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001469 done = 1;
1470 unlock_page(page);
1471 break;
1472 }
1473
1474 if (next && (page->index != next)) {
1475 /* Not next consecutive page */
1476 unlock_page(page);
1477 break;
1478 }
1479
1480 if (wbc->sync_mode != WB_SYNC_NONE)
1481 wait_on_page_writeback(page);
1482
1483 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001484 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001485 unlock_page(page);
1486 break;
1487 }
Steve French84d2f072005-10-12 15:32:05 -07001488
Linus Torvaldscb876f42006-12-23 16:19:07 -08001489 /*
1490 * This actually clears the dirty bit in the radix tree.
1491 * See cifs_writepage() for more commentary.
1492 */
1493 set_page_writeback(page);
1494
Steve French84d2f072005-10-12 15:32:05 -07001495 if (page_offset(page) >= mapping->host->i_size) {
1496 done = 1;
1497 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001498 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001499 break;
1500 }
1501
Steve French37c0eb42005-10-05 14:50:29 -07001502 /*
1503 * BB can we get rid of this? pages are held by pvec
1504 */
1505 page_cache_get(page);
1506
Steve French84d2f072005-10-12 15:32:05 -07001507 len = min(mapping->host->i_size - page_offset(page),
1508 (loff_t)PAGE_CACHE_SIZE);
1509
Steve French37c0eb42005-10-05 14:50:29 -07001510 /* reserve iov[0] for the smb header */
1511 n_iov++;
1512 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001513 iov[n_iov].iov_len = len;
1514 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001515
1516 if (first < 0) {
1517 first = i;
1518 offset = page_offset(page);
1519 }
1520 next = page->index + 1;
1521 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1522 break;
1523 }
1524 if (n_iov) {
Jeff Layton6508d902010-09-29 19:51:11 -04001525 open_file = find_writable_file(CIFS_I(mapping->host),
1526 false);
Steve French23e7dd72005-10-20 13:44:56 -07001527 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001528 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001529 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001530 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001531 long_op = cifs_write_timeout(cifsi, offset);
Jeff Laytonf3983c22010-09-22 16:17:40 -07001532 rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
Steve French23e7dd72005-10-20 13:44:56 -07001533 bytes_to_write, offset,
1534 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001535 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001536 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001537 cifs_update_eof(cifsi, offset, bytes_written);
Steve French37c0eb42005-10-05 14:50:29 -07001538 }
Jeff Laytonf3983c22010-09-22 16:17:40 -07001539
1540 if (rc || bytes_written < bytes_to_write) {
1541 cERROR(1, "Write2 ret %d, wrote %d",
1542 rc, bytes_written);
1543 /* BB what if continued retry is
1544 requested via mount flags? */
1545 if (rc == -ENOSPC)
1546 set_bit(AS_ENOSPC, &mapping->flags);
1547 else
1548 set_bit(AS_EIO, &mapping->flags);
1549 } else {
1550 cifs_stats_bytes_written(tcon, bytes_written);
1551 }
1552
Steve French37c0eb42005-10-05 14:50:29 -07001553 for (i = 0; i < n_iov; i++) {
1554 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001555 /* Should we also set page error on
1556 success rc but too little data written? */
1557 /* BB investigate retry logic on temporary
1558 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001559 when page marked as error */
1560 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001561 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001562 kunmap(page);
1563 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001564 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001565 page_cache_release(page);
1566 }
1567 if ((wbc->nr_to_write -= n_iov) <= 0)
1568 done = 1;
1569 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001570 } else
1571 /* Need to re-find the pages we skipped */
1572 index = pvec.pages[0]->index + 1;
1573
Steve French37c0eb42005-10-05 14:50:29 -07001574 pagevec_release(&pvec);
1575 }
1576 if (!scanned && !done) {
1577 /*
1578 * We hit the last page and there is more work to be done: wrap
1579 * back to the start of the file
1580 */
1581 scanned = 1;
1582 index = 0;
1583 goto retry;
1584 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001585 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001586 mapping->writeback_index = index;
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001589 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return rc;
1591}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001593static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
1595 int rc = -EFAULT;
1596 int xid;
1597
1598 xid = GetXid();
1599/* BB add check for wbc flags */
1600 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001601 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001602 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001603
1604 /*
1605 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1606 *
1607 * A writepage() implementation always needs to do either this,
1608 * or re-dirty the page with "redirty_page_for_writepage()" in
1609 * the case of a failure.
1610 *
1611 * Just unlocking the page will cause the radix tree tag-bits
1612 * to fail to update with the state of the page correctly.
1613 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001614 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1616 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1617 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001618 end_page_writeback(page);
1619 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 FreeXid(xid);
1621 return rc;
1622}
1623
Nick Piggind9414772008-09-24 11:32:59 -04001624static int cifs_write_end(struct file *file, struct address_space *mapping,
1625 loff_t pos, unsigned len, unsigned copied,
1626 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627{
Nick Piggind9414772008-09-24 11:32:59 -04001628 int rc;
1629 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Joe Perchesb6b38f72010-04-21 03:50:45 +00001631 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1632 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001633
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001634 if (PageChecked(page)) {
1635 if (copied == len)
1636 SetPageUptodate(page);
1637 ClearPageChecked(page);
1638 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001639 SetPageUptodate(page);
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001642 char *page_data;
1643 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1644 int xid;
1645
1646 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 /* this is probably better than directly calling
1648 partialpage_write since in this function the file handle is
1649 known which we might as well leverage */
1650 /* BB check if anything else missing out of ppw
1651 such as updating last write time */
1652 page_data = kmap(page);
Jeff Layton7da4b492010-10-15 15:34:00 -04001653 rc = cifs_write(file->private_data, page_data + offset,
1654 copied, &pos);
Nick Piggind9414772008-09-24 11:32:59 -04001655 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001657
1658 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001659 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001660 rc = copied;
1661 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 set_page_dirty(page);
1663 }
1664
Nick Piggind9414772008-09-24 11:32:59 -04001665 if (rc > 0) {
1666 spin_lock(&inode->i_lock);
1667 if (pos > inode->i_size)
1668 i_size_write(inode, pos);
1669 spin_unlock(&inode->i_lock);
1670 }
1671
1672 unlock_page(page);
1673 page_cache_release(page);
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 return rc;
1676}
1677
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001678int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679{
1680 int xid;
1681 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001682 struct cifsTconInfo *tcon;
Joe Perchesc21dfb62010-07-12 13:50:14 -07001683 struct cifsFileInfo *smbfile = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001684 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
1686 xid = GetXid();
1687
Joe Perchesb6b38f72010-04-21 03:50:45 +00001688 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001689 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001690
Jeff Laytoncea21802007-11-20 23:19:03 +00001691 rc = filemap_write_and_wait(inode->i_mapping);
1692 if (rc == 0) {
1693 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 CIFS_I(inode)->write_behind_rc = 0;
Jeff Layton13cfb732010-09-29 19:51:11 -04001695 tcon = tlink_tcon(smbfile->tlink);
Steve Frenchbe652442009-02-23 15:21:59 +00001696 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001697 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001698 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001699 }
Steve Frenchb298f222009-02-21 21:17:43 +00001700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 FreeXid(xid);
1702 return rc;
1703}
1704
NeilBrown3978d7172006-03-26 01:37:17 -08001705/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706{
1707 struct address_space *mapping;
1708 struct inode *inode;
1709 unsigned long index = page->index;
1710 unsigned int rpages = 0;
1711 int rc = 0;
1712
Steve Frenchf19159d2010-04-21 04:12:10 +00001713 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 mapping = page->mapping;
1715 if (!mapping)
1716 return 0;
1717 inode = mapping->host;
1718 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001719 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001721/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1723
Joe Perchesb6b38f72010-04-21 03:50:45 +00001724/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
NeilBrown3978d7172006-03-26 01:37:17 -08001726#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc < 0)
1728 return rc;
1729 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001730#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731} */
1732
1733/*
1734 * As file closes, flush all cached write data for this inode checking
1735 * for write behind errors.
1736 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001737int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 int rc = 0;
1741
1742 /* Rather than do the steps manually:
1743 lock the inode for writing
1744 loop through pages looking for write behind data (dirty pages)
1745 coalesce into contiguous 16K (or smaller) chunks to write to server
1746 send to server (prefer in parallel)
1747 deal with writebehind errors
1748 unlock inode for writing
1749 filemapfdatawrite appears easier for the time being */
1750
1751 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001752 /* reset wb rc if we were able to write out dirty pages */
1753 if (!rc) {
1754 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001756 }
Steve French50c2f752007-07-13 00:33:32 +00001757
Joe Perchesb6b38f72010-04-21 03:50:45 +00001758 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 return rc;
1761}
1762
1763ssize_t cifs_user_read(struct file *file, char __user *read_data,
1764 size_t read_size, loff_t *poffset)
1765{
1766 int rc = -EACCES;
1767 unsigned int bytes_read = 0;
1768 unsigned int total_read = 0;
1769 unsigned int current_read_size;
1770 struct cifs_sb_info *cifs_sb;
1771 struct cifsTconInfo *pTcon;
1772 int xid;
1773 struct cifsFileInfo *open_file;
1774 char *smb_read_data;
1775 char __user *current_offset;
1776 struct smb_com_read_rsp *pSMBr;
1777
1778 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001779 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
1781 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301782 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301784 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001786 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001787 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
Steve Frenchad7a2922008-02-07 23:25:02 +00001789 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001790 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 for (total_read = 0, current_offset = read_data;
1793 read_size > total_read;
1794 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001795 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 cifs_sb->rsize);
1797 rc = -EAGAIN;
1798 smb_read_data = NULL;
1799 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001800 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001801 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 (!open_file->closePend)) {
Jeff Layton15886172010-10-15 15:33:59 -04001803 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 if (rc != 0)
1805 break;
1806 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001807 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001808 open_file->netfid,
1809 current_read_size, *poffset,
1810 &bytes_read, &smb_read_data,
1811 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001814 if (copy_to_user(current_offset,
1815 smb_read_data +
1816 4 /* RFC1001 length field */ +
1817 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001818 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001819 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001820
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001822 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001823 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001824 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 smb_read_data = NULL;
1826 }
1827 }
1828 if (rc || (bytes_read == 0)) {
1829 if (total_read) {
1830 break;
1831 } else {
1832 FreeXid(xid);
1833 return rc;
1834 }
1835 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001836 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 *poffset += bytes_read;
1838 }
1839 }
1840 FreeXid(xid);
1841 return total_read;
1842}
1843
1844
1845static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1846 loff_t *poffset)
1847{
1848 int rc = -EACCES;
1849 unsigned int bytes_read = 0;
1850 unsigned int total_read;
1851 unsigned int current_read_size;
1852 struct cifs_sb_info *cifs_sb;
1853 struct cifsTconInfo *pTcon;
1854 int xid;
1855 char *current_offset;
1856 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001857 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001860 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301863 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301865 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07001867 open_file = file->private_data;
Jeff Layton13cfb732010-09-29 19:51:11 -04001868 pTcon = tlink_tcon(open_file->tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001871 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001873 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 read_size > total_read;
1875 total_read += bytes_read, current_offset += bytes_read) {
1876 current_read_size = min_t(const int, read_size - total_read,
1877 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001878 /* For windows me and 9x we do not want to request more
1879 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001880 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001881 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1882 current_read_size = min_t(const int, current_read_size,
1883 pTcon->ses->server->maxBuf - 128);
1884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 rc = -EAGAIN;
1886 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001887 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 (!open_file->closePend)) {
Jeff Layton15886172010-10-15 15:33:59 -04001889 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (rc != 0)
1891 break;
1892 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001893 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001894 open_file->netfid,
1895 current_read_size, *poffset,
1896 &bytes_read, &current_offset,
1897 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
1899 if (rc || (bytes_read == 0)) {
1900 if (total_read) {
1901 break;
1902 } else {
1903 FreeXid(xid);
1904 return rc;
1905 }
1906 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001907 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 *poffset += bytes_read;
1909 }
1910 }
1911 FreeXid(xid);
1912 return total_read;
1913}
1914
1915int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1916{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 int rc, xid;
1918
1919 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001920 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001922 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 FreeXid(xid);
1924 return rc;
1925 }
1926 rc = generic_file_mmap(file, vma);
1927 FreeXid(xid);
1928 return rc;
1929}
1930
1931
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001932static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001933 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934{
1935 struct page *page;
1936 char *target;
1937
1938 while (bytes_read > 0) {
1939 if (list_empty(pages))
1940 break;
1941
1942 page = list_entry(pages->prev, struct page, lru);
1943 list_del(&page->lru);
1944
Nick Piggin315e9952010-04-21 03:18:28 +00001945 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 GFP_KERNEL)) {
1947 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001948 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001949 data += PAGE_CACHE_SIZE;
1950 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 continue;
1952 }
Jeff Layton06b43672010-06-01 10:54:45 -04001953 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001955 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
1957 if (PAGE_CACHE_SIZE > bytes_read) {
1958 memcpy(target, data, bytes_read);
1959 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001960 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 PAGE_CACHE_SIZE - bytes_read);
1962 bytes_read = 0;
1963 } else {
1964 memcpy(target, data, PAGE_CACHE_SIZE);
1965 bytes_read -= PAGE_CACHE_SIZE;
1966 }
1967 kunmap_atomic(target, KM_USER0);
1968
1969 flush_dcache_page(page);
1970 SetPageUptodate(page);
1971 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 data += PAGE_CACHE_SIZE;
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05301973
1974 /* add page to FS-Cache */
1975 cifs_readpage_to_fscache(mapping->host, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 }
1977 return;
1978}
1979
1980static int cifs_readpages(struct file *file, struct address_space *mapping,
1981 struct list_head *page_list, unsigned num_pages)
1982{
1983 int rc = -EACCES;
1984 int xid;
1985 loff_t offset;
1986 struct page *page;
1987 struct cifs_sb_info *cifs_sb;
1988 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001989 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001990 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 char *smb_read_data = NULL;
1992 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001994 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
1996 xid = GetXid();
1997 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301998 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302000 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
Joe Perchesc21dfb62010-07-12 13:50:14 -07002002 open_file = file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002003 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Jeff Layton13cfb732010-09-29 19:51:11 -04002004 pTcon = tlink_tcon(open_file->tlink);
Steve Frenchbfa0d752005-08-31 21:50:37 -07002005
Suresh Jayaraman56698232010-07-05 18:13:25 +05302006 /*
2007 * Reads as many pages as possible from fscache. Returns -ENOBUFS
2008 * immediately if the cookie is negative
2009 */
2010 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
2011 &num_pages);
2012 if (rc == 0)
2013 goto read_complete;
2014
Steve Frenchf19159d2010-04-21 04:12:10 +00002015 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 for (i = 0; i < num_pages; ) {
2017 unsigned contig_pages;
2018 struct page *tmp_page;
2019 unsigned long expected_index;
2020
2021 if (list_empty(page_list))
2022 break;
2023
2024 page = list_entry(page_list->prev, struct page, lru);
2025 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2026
2027 /* count adjacent pages that we will read into */
2028 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002029 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002031 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (tmp_page->index == expected_index) {
2033 contig_pages++;
2034 expected_index++;
2035 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
2038 if (contig_pages + i > num_pages)
2039 contig_pages = num_pages - i;
2040
2041 /* for reads over a certain size could initiate async
2042 read ahead */
2043
2044 read_size = contig_pages * PAGE_CACHE_SIZE;
2045 /* Read size needs to be in multiples of one page */
2046 read_size = min_t(const unsigned int, read_size,
2047 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002048 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
2049 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 rc = -EAGAIN;
2051 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 (!open_file->closePend)) {
Jeff Layton15886172010-10-15 15:33:59 -04002054 rc = cifs_reopen_file(open_file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if (rc != 0)
2056 break;
2057 }
2058
Steve Frenchbfa0d752005-08-31 21:50:37 -07002059 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002060 open_file->netfid,
2061 read_size, offset,
2062 &bytes_read, &smb_read_data,
2063 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002064 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002065 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002067 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002068 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002069 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002070 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 smb_read_data = NULL;
2072 }
2073 }
2074 }
2075 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002076 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 break;
2078 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002079 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2081 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2082 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002083 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002086 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002087 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 i++; /* account for partial page */
2089
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092 /* BB do we need to verify this common case ?
2093 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 we will hit it on next read */
2095
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002096 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 }
2098 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002099 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002100 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002101 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002102 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 break;
2105 }
2106 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002107 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002108 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002109 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002110 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 smb_read_data = NULL;
2112 }
2113 bytes_read = 0;
2114 }
2115
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116/* need to free smb_read_data buf before exit */
2117 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002118 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002119 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002120 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002121 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
Suresh Jayaraman56698232010-07-05 18:13:25 +05302125read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 FreeXid(xid);
2127 return rc;
2128}
2129
2130static int cifs_readpage_worker(struct file *file, struct page *page,
2131 loff_t *poffset)
2132{
2133 char *read_data;
2134 int rc;
2135
Suresh Jayaraman56698232010-07-05 18:13:25 +05302136 /* Is the page cached? */
2137 rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
2138 if (rc == 0)
2139 goto read_complete;
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 page_cache_get(page);
2142 read_data = kmap(page);
2143 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002146
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 if (rc < 0)
2148 goto io_error;
2149 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002150 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002151
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002152 file->f_path.dentry->d_inode->i_atime =
2153 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002154
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 if (PAGE_CACHE_SIZE > rc)
2156 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2157
2158 flush_dcache_page(page);
2159 SetPageUptodate(page);
Suresh Jayaraman9dc06552010-07-05 18:13:11 +05302160
2161 /* send this page to the cache */
2162 cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002167 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 page_cache_release(page);
Suresh Jayaraman56698232010-07-05 18:13:25 +05302169
2170read_complete:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 return rc;
2172}
2173
2174static int cifs_readpage(struct file *file, struct page *page)
2175{
2176 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2177 int rc = -EACCES;
2178 int xid;
2179
2180 xid = GetXid();
2181
2182 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302183 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302185 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 }
2187
Joe Perchesb6b38f72010-04-21 03:50:45 +00002188 cFYI(1, "readpage %p at offset %d 0x%x\n",
2189 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
2191 rc = cifs_readpage_worker(file, page, &offset);
2192
2193 unlock_page(page);
2194
2195 FreeXid(xid);
2196 return rc;
2197}
2198
Steve Frencha403a0a2007-07-26 15:54:16 +00002199static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2200{
2201 struct cifsFileInfo *open_file;
2202
2203 read_lock(&GlobalSMBSeslock);
2204 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2205 if (open_file->closePend)
2206 continue;
Jeff Layton2e396b82010-10-15 15:34:01 -04002207 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
Steve Frencha403a0a2007-07-26 15:54:16 +00002208 read_unlock(&GlobalSMBSeslock);
2209 return 1;
2210 }
2211 }
2212 read_unlock(&GlobalSMBSeslock);
2213 return 0;
2214}
2215
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216/* We do not want to update the file size from server for inodes
2217 open for write - to avoid races with writepage extending
2218 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002219 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 but this is tricky to do without racing with writebehind
2221 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002222bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223{
Steve Frencha403a0a2007-07-26 15:54:16 +00002224 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002225 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002226
Steve Frencha403a0a2007-07-26 15:54:16 +00002227 if (is_inode_writable(cifsInode)) {
2228 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002229 struct cifs_sb_info *cifs_sb;
2230
Steve Frenchc32a0b62006-01-12 14:41:28 -08002231 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002232 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002233 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002234 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002235 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002236 }
2237
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002238 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002239 return true;
Steve French7ba52632007-02-08 18:14:13 +00002240
Steve French4b18f2a2008-04-29 00:06:05 +00002241 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002242 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002243 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244}
2245
Nick Piggind9414772008-09-24 11:32:59 -04002246static int cifs_write_begin(struct file *file, struct address_space *mapping,
2247 loff_t pos, unsigned len, unsigned flags,
2248 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249{
Nick Piggind9414772008-09-24 11:32:59 -04002250 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2251 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002252 loff_t page_start = pos & PAGE_MASK;
2253 loff_t i_size;
2254 struct page *page;
2255 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Joe Perchesb6b38f72010-04-21 03:50:45 +00002257 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002258
Nick Piggin54566b22009-01-04 12:00:53 -08002259 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002260 if (!page) {
2261 rc = -ENOMEM;
2262 goto out;
2263 }
Nick Piggind9414772008-09-24 11:32:59 -04002264
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002265 if (PageUptodate(page))
2266 goto out;
Steve French8a236262007-03-06 00:31:00 +00002267
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002268 /*
2269 * If we write a full page it will be up to date, no need to read from
2270 * the server. If the write is short, we'll end up doing a sync write
2271 * instead.
2272 */
2273 if (len == PAGE_CACHE_SIZE)
2274 goto out;
2275
2276 /*
2277 * optimize away the read when we have an oplock, and we're not
2278 * expecting to use any of the data we'd be reading in. That
2279 * is, when the page lies beyond the EOF, or straddles the EOF
2280 * and the write will cover all of the existing data.
2281 */
2282 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2283 i_size = i_size_read(mapping->host);
2284 if (page_start >= i_size ||
2285 (offset == 0 && (pos + len) >= i_size)) {
2286 zero_user_segments(page, 0, offset,
2287 offset + len,
2288 PAGE_CACHE_SIZE);
2289 /*
2290 * PageChecked means that the parts of the page
2291 * to which we're not writing are considered up
2292 * to date. Once the data is copied to the
2293 * page, it can be set uptodate.
2294 */
2295 SetPageChecked(page);
2296 goto out;
2297 }
2298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Nick Piggind9414772008-09-24 11:32:59 -04002300 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002301 /*
2302 * might as well read a page, it is fast enough. If we get
2303 * an error, we don't need to return it. cifs_write_end will
2304 * do a sync write instead since PG_uptodate isn't set.
2305 */
2306 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002307 } else {
2308 /* we could try using another file handle if there is one -
2309 but how would we lock it to prevent close of that handle
2310 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002311 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002312 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002313out:
2314 *pagep = page;
2315 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316}
2317
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302318static int cifs_release_page(struct page *page, gfp_t gfp)
2319{
2320 if (PagePrivate(page))
2321 return 0;
2322
2323 return cifs_fscache_release_page(page, gfp);
2324}
2325
2326static void cifs_invalidate_page(struct page *page, unsigned long offset)
2327{
2328 struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
2329
2330 if (offset == 0)
2331 cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
2332}
2333
Tejun Heo9b646972010-07-20 22:09:02 +02002334void cifs_oplock_break(struct work_struct *work)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002335{
2336 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2337 oplock_break);
Jeff Laytona5e18bc2010-10-11 15:07:18 -04002338 struct inode *inode = cfile->dentry->d_inode;
Jeff Layton3bc303c2009-09-21 06:47:50 -04002339 struct cifsInodeInfo *cinode = CIFS_I(inode);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002340 int rc, waitrc = 0;
2341
2342 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002343 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002344 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002345 else
Al Viro8737c932009-12-24 06:47:55 -05002346 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002347 rc = filemap_fdatawrite(inode->i_mapping);
2348 if (cinode->clientCanCacheRead == 0) {
2349 waitrc = filemap_fdatawait(inode->i_mapping);
2350 invalidate_remote_inode(inode);
2351 }
2352 if (!rc)
2353 rc = waitrc;
2354 if (rc)
2355 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002356 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002357 }
2358
2359 /*
2360 * releasing stale oplock after recent reconnect of smb session using
2361 * a now incorrect file handle is not a data integrity issue but do
2362 * not bother sending an oplock release if session to server still is
2363 * disconnected since oplock already released by the server
2364 */
2365 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
Jeff Layton13cfb732010-09-29 19:51:11 -04002366 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
2367 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002368 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002369 }
Tejun Heo9b646972010-07-20 22:09:02 +02002370
2371 /*
2372 * We might have kicked in before is_valid_oplock_break()
2373 * finished grabbing reference for us. Make sure it's done by
2374 * waiting for GlobalSMSSeslock.
2375 */
2376 write_lock(&GlobalSMBSeslock);
2377 write_unlock(&GlobalSMBSeslock);
2378
2379 cifs_oplock_break_put(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002380}
2381
Tejun Heo9b646972010-07-20 22:09:02 +02002382void cifs_oplock_break_get(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002383{
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002384 cifs_sb_active(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002385 cifsFileInfo_get(cfile);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002386}
2387
Tejun Heo9b646972010-07-20 22:09:02 +02002388void cifs_oplock_break_put(struct cifsFileInfo *cfile)
Jeff Layton3bc303c2009-09-21 06:47:50 -04002389{
Jeff Layton3bc303c2009-09-21 06:47:50 -04002390 cifsFileInfo_put(cfile);
Jeff Laytond7c86ff2010-10-11 15:07:19 -04002391 cifs_sb_deactive(cfile->dentry->d_sb);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002392}
2393
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002394const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 .readpage = cifs_readpage,
2396 .readpages = cifs_readpages,
2397 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002398 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002399 .write_begin = cifs_write_begin,
2400 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302402 .releasepage = cifs_release_page,
2403 .invalidatepage = cifs_invalidate_page,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 /* .sync_page = cifs_sync_page, */
2405 /* .direct_IO = */
2406};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002407
2408/*
2409 * cifs_readpages requires the server to support a buffer large enough to
2410 * contain the header plus one complete page of data. Otherwise, we need
2411 * to leave cifs_readpages out of the address space operations.
2412 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002413const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002414 .readpage = cifs_readpage,
2415 .writepage = cifs_writepage,
2416 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002417 .write_begin = cifs_write_begin,
2418 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002419 .set_page_dirty = __set_page_dirty_nobuffers,
Suresh Jayaraman85f2d6b2010-07-05 18:13:00 +05302420 .releasepage = cifs_release_page,
2421 .invalidatepage = cifs_invalidate_page,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002422 /* .sync_page = cifs_sync_page, */
2423 /* .direct_IO = */
2424};