blob: 9cbf0f097a39d77333dee7a18c708efb0ae58630 [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"
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static inline int cifs_convert_flags(unsigned int flags)
45{
46 if ((flags & O_ACCMODE) == O_RDONLY)
47 return GENERIC_READ;
48 else if ((flags & O_ACCMODE) == O_WRONLY)
49 return GENERIC_WRITE;
50 else if ((flags & O_ACCMODE) == O_RDWR) {
51 /* GENERIC_ALL is too much permission to request
52 can cause unnecessary access denied on create */
53 /* return GENERIC_ALL; */
54 return (GENERIC_READ | GENERIC_WRITE);
55 }
56
Jeff Laytone10f7b52008-05-14 10:21:33 -070057 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
58 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
59 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000060}
Jeff Laytone10f7b52008-05-14 10:21:33 -070061
Steve French7fc8f4e2009-02-23 20:43:11 +000062static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
63{
64 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070065
Steve French7fc8f4e2009-02-23 20:43:11 +000066 if ((flags & O_ACCMODE) == O_RDONLY)
67 posix_flags = FMODE_READ;
68 else if ((flags & O_ACCMODE) == O_WRONLY)
69 posix_flags = FMODE_WRITE;
70 else if ((flags & O_ACCMODE) == O_RDWR) {
71 /* GENERIC_ALL is too much permission to request
72 can cause unnecessary access denied on create */
73 /* return GENERIC_ALL; */
74 posix_flags = FMODE_READ | FMODE_WRITE;
75 }
76 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
77 reopening a file. They had their effect on the original open */
78 if (flags & O_APPEND)
79 posix_flags |= (fmode_t)O_APPEND;
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010080 if (flags & O_DSYNC)
81 posix_flags |= (fmode_t)O_DSYNC;
82 if (flags & __O_SYNC)
83 posix_flags |= (fmode_t)__O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000084 if (flags & O_DIRECTORY)
85 posix_flags |= (fmode_t)O_DIRECTORY;
86 if (flags & O_NOFOLLOW)
87 posix_flags |= (fmode_t)O_NOFOLLOW;
88 if (flags & O_DIRECT)
89 posix_flags |= (fmode_t)O_DIRECT;
90
91 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
93
94static inline int cifs_get_disposition(unsigned int flags)
95{
96 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
97 return FILE_CREATE;
98 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
99 return FILE_OVERWRITE_IF;
100 else if ((flags & O_CREAT) == O_CREAT)
101 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000102 else if ((flags & O_TRUNC) == O_TRUNC)
103 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 else
105 return FILE_OPEN;
106}
107
108/* all arguments to this function must be checked for validity in caller */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400109static inline int
110cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530111 struct cifsInodeInfo *pCifsInode, __u32 oplock,
Jeff Layton590a3fe2009-09-12 11:54:28 -0400112 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000113{
Steve French276a74a2009-03-03 18:00:34 +0000114
Steve French276a74a2009-03-03 18:00:34 +0000115 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000116
117 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
118 if (pCifsInode == NULL) {
119 write_unlock(&GlobalSMBSeslock);
120 return -EINVAL;
121 }
122
Steve French276a74a2009-03-03 18:00:34 +0000123 if (pCifsInode->clientCanCacheRead) {
124 /* we have the inode open somewhere else
125 no need to discard cache data */
126 goto psx_client_can_cache;
127 }
128
129 /* BB FIXME need to fix this check to move it earlier into posix_open
130 BB fIX following section BB FIXME */
131
132 /* if not oplocked, invalidate inode pages if mtime or file
133 size changed */
134/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
135 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
136 (file->f_path.dentry->d_inode->i_size ==
137 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000138 cFYI(1, "inode unchanged on server");
Steve French276a74a2009-03-03 18:00:34 +0000139 } else {
140 if (file->f_path.dentry->d_inode->i_mapping) {
141 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
142 if (rc != 0)
143 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
144 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000145 cFYI(1, "invalidating remote inode since open detected it "
146 "changed");
Steve French276a74a2009-03-03 18:00:34 +0000147 invalidate_remote_inode(file->f_path.dentry->d_inode);
148 } */
149
150psx_client_can_cache:
151 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
152 pCifsInode->clientCanCacheAll = true;
153 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000154 cFYI(1, "Exclusive Oplock granted on inode %p",
155 file->f_path.dentry->d_inode);
Steve French276a74a2009-03-03 18:00:34 +0000156 } else if ((oplock & 0xF) == OPLOCK_READ)
157 pCifsInode->clientCanCacheRead = true;
158
159 /* will have to change the unlock if we reenable the
160 filemap_fdatawrite (which does not seem necessary */
161 write_unlock(&GlobalSMBSeslock);
162 return 0;
163}
164
165/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
167 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
168 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
169 char *full_path, int xid)
170{
171 struct timespec temp;
172 int rc;
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (pCifsInode->clientCanCacheRead) {
175 /* we have the inode open somewhere else
176 no need to discard cache data */
177 goto client_can_cache;
178 }
179
180 /* BB need same check in cifs_create too? */
181 /* if not oplocked, invalidate inode pages if mtime or file
182 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400183 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800184 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
185 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000187 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800189 if (file->f_path.dentry->d_inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000190 /* BB no need to lock inode until after invalidate
191 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000192 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
193 if (rc != 0)
194 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000196 cFYI(1, "invalidating remote inode since open detected it "
197 "changed");
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800198 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
200
201client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000202 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800203 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 full_path, inode->i_sb, xid);
205 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800206 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000207 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000210 pCifsInode->clientCanCacheAll = true;
211 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000212 cFYI(1, "Exclusive Oplock granted on inode %p",
213 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000215 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 return rc;
218}
219
220int cifs_open(struct inode *inode, struct file *file)
221{
222 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400223 int xid;
224 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000226 struct cifsTconInfo *tcon;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400227 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 char *full_path = NULL;
230 int desiredAccess;
231 int disposition;
232 __u16 netfid;
233 FILE_ALL_INFO *buf = NULL;
234
235 xid = GetXid();
236
237 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000238 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Steve Frencha6ce4932009-04-09 01:14:32 +0000240 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800242 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530244 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530246 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248
Joe Perchesb6b38f72010-04-21 03:50:45 +0000249 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
250 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000251
252 if (oplockEnabled)
253 oplock = REQ_OPLOCK;
254 else
255 oplock = 0;
256
Steve French64cc2c62009-03-04 19:54:08 +0000257 if (!tcon->broken_posix_open && tcon->unix_ext &&
258 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000259 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
260 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
261 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
Steve Frenchfa588e02010-04-22 19:21:55 +0000262 oflags |= SMB_O_CREAT;
Steve French276a74a2009-03-03 18:00:34 +0000263 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400264 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000265 cifs_sb->mnt_file_mode /* ignored */,
266 oflags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000267 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000268 cFYI(1, "posix open succeeded");
Steve French276a74a2009-03-03 18:00:34 +0000269 /* no need for special case handling of setting mode
270 on read only files needed here */
271
Jeff Layton2422f672010-06-16 13:40:16 -0400272 pCifsFile = cifs_new_fileinfo(inode, netfid, file,
273 file->f_path.mnt,
274 oflags);
275 if (pCifsFile == NULL) {
276 CIFSSMBClose(xid, tcon, netfid);
277 rc = -ENOMEM;
278 goto out;
279 }
Jeff Layton2422f672010-06-16 13:40:16 -0400280
Steve French276a74a2009-03-03 18:00:34 +0000281 cifs_posix_open_inode_helper(inode, file, pCifsInode,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530282 oplock, netfid);
Steve French276a74a2009-03-03 18:00:34 +0000283 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000284 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
285 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000286 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000287 " unexpected error on SMB posix open"
288 ", disabling posix open support."
289 " Check if server update available.",
290 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000291 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000292 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000293 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
294 (rc != -EOPNOTSUPP)) /* path not found or net err */
295 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000296 /* else fallthrough to retry open the old way on network i/o
297 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000298 }
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 desiredAccess = cifs_convert_flags(file->f_flags);
301
302/*********************************************************************
303 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000304 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 * O_CREAT FILE_OPEN_IF
308 * O_CREAT | O_EXCL FILE_CREATE
309 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
310 * O_TRUNC FILE_OVERWRITE
311 * none of the above FILE_OPEN
312 *
313 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000314 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 * O_CREAT | O_TRUNC is similar but truncates the existing
316 * file rather than creating a new file as FILE_SUPERSEDE does
317 * (which uses the attributes / metadata passed in on open call)
318 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000319 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 *? and the read write flags match reasonably. O_LARGEFILE
321 *? is irrelevant because largefile support is always used
322 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
323 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
324 *********************************************************************/
325
326 disposition = cifs_get_disposition(file->f_flags);
327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 /* BB pass O_SYNC flag through on file attributes .. BB */
329
330 /* Also refresh inode by passing in file_info buf returned by SMBOpen
331 and calling get_inode_info with returned buf (at least helps
332 non-Unix server case) */
333
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000334 /* BB we can not do this if this is the second open of a file
335 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
337 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
338 if (!buf) {
339 rc = -ENOMEM;
340 goto out;
341 }
Steve French5bafd762006-06-07 00:18:43 +0000342
343 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000344 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000345 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700346 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
347 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000348 else
349 rc = -EIO; /* no NT SMB support fall into legacy open below */
350
Steve Frencha9d02ad2005-08-24 23:06:05 -0700351 if (rc == -EIO) {
352 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000353 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700354 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
355 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
356 & CIFS_MOUNT_MAP_SPECIAL_CHR);
357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000359 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 goto out;
361 }
Jeff Layton3321b792009-09-25 09:53:37 -0400362
Jeff Layton086f68b2009-09-21 14:08:18 -0400363 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
364 file->f_flags);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400365 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 rc = -ENOMEM;
367 goto out;
368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Jeff Layton3321b792009-09-25 09:53:37 -0400370 rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
371 &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000373 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 /* time to set mode which we can not set earlier due to
375 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000376 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400377 struct cifs_unix_set_info_args args = {
378 .mode = inode->i_mode,
379 .uid = NO_CHANGE_64,
380 .gid = NO_CHANGE_64,
381 .ctime = NO_CHANGE_64,
382 .atime = NO_CHANGE_64,
383 .mtime = NO_CHANGE_64,
384 .device = 0,
385 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400386 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
387 cifs_sb->local_nls,
388 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700389 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 }
391 }
392
393out:
394 kfree(buf);
395 kfree(full_path);
396 FreeXid(xid);
397 return rc;
398}
399
Adrian Bunk04187262006-06-30 18:23:04 +0200400/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401/* to server was lost */
402static int cifs_relock_file(struct cifsFileInfo *cifsFile)
403{
404 int rc = 0;
405
406/* BB list all locks open on this file and relock */
407
408 return rc;
409}
410
Steve French4b18f2a2008-04-29 00:06:05 +0000411static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
413 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400414 int xid;
415 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000417 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 struct cifsFileInfo *pCifsFile;
419 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000420 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 char *full_path = NULL;
422 int desiredAccess;
423 int disposition = FILE_OPEN;
424 __u16 netfid;
425
Steve Frenchad7a2922008-02-07 23:25:02 +0000426 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000428 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return -EBADF;
430
431 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400432 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000433 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400434 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530435 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530437 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
439
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800440 if (file->f_path.dentry == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000441 cERROR(1, "no valid name if dentry freed");
Steve French3a9f4622007-04-04 17:10:24 +0000442 dump_stack();
443 rc = -EBADF;
444 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Steve French3a9f4622007-04-04 17:10:24 +0000446
447 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 if (inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000449 cERROR(1, "inode not valid");
Steve French3a9f4622007-04-04 17:10:24 +0000450 dump_stack();
451 rc = -EBADF;
452 goto reopen_error_exit;
453 }
Steve French50c2f752007-07-13 00:33:32 +0000454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000456 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458/* can not grab rename sem here because various ops, including
459 those that already have the rename sem can end up causing writepage
460 to get called and if the server was down that means we end up here,
461 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800462 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000464 rc = -ENOMEM;
465reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400466 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000468 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
470
Joe Perchesb6b38f72010-04-21 03:50:45 +0000471 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
472 inode, file->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
474 if (oplockEnabled)
475 oplock = REQ_OPLOCK;
476 else
Steve French4b18f2a2008-04-29 00:06:05 +0000477 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Steve French7fc8f4e2009-02-23 20:43:11 +0000479 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
480 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
481 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
482 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
483 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400484 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000485 cifs_sb->mnt_file_mode /* ignored */,
486 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000487 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000488 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000489 goto reopen_success;
490 }
491 /* fallthrough to retry open the old way on errors, especially
492 in the reconnect path it is important to retry hard */
493 }
494
495 desiredAccess = cifs_convert_flags(file->f_flags);
496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000498 by SMBOpen and then calling get_inode_info with returned buf
499 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 and server version of file size can be stale. If we knew for sure
501 that inode was not dirty locally we could do this */
502
Steve French7fc8f4e2009-02-23 20:43:11 +0000503 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000505 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700506 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400508 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000509 cFYI(1, "cifs_open returned 0x%x", rc);
510 cFYI(1, "oplock: %d", oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000512reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000514 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400515 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 pCifsInode = CIFS_I(inode);
517 if (pCifsInode) {
518 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000519 rc = filemap_write_and_wait(inode->i_mapping);
520 if (rc != 0)
521 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 /* temporarily disable caching while we
523 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000524 pCifsInode->clientCanCacheAll = false;
525 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000526 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 rc = cifs_get_inode_info_unix(&inode,
528 full_path, inode->i_sb, xid);
529 else
530 rc = cifs_get_inode_info(&inode,
531 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000532 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 } /* else we are writing out data to server already
534 and could deadlock if we tried to flush data, and
535 since we do not know if we have data that would
536 invalidate the current end of file on the server
537 we can not go to the server to get the new inod
538 info */
539 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000540 pCifsInode->clientCanCacheAll = true;
541 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cFYI(1, "Exclusive Oplock granted on inode %p",
543 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000545 pCifsInode->clientCanCacheRead = true;
546 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000548 pCifsInode->clientCanCacheRead = false;
549 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
551 cifs_relock_file(pCifsFile);
552 }
553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 kfree(full_path);
555 FreeXid(xid);
556 return rc;
557}
558
559int cifs_close(struct inode *inode, struct file *file)
560{
561 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000562 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 struct cifs_sb_info *cifs_sb;
564 struct cifsTconInfo *pTcon;
565 struct cifsFileInfo *pSMBFile =
566 (struct cifsFileInfo *)file->private_data;
567
568 xid = GetXid();
569
570 cifs_sb = CIFS_SB(inode->i_sb);
571 pTcon = cifs_sb->tcon;
572 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000573 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000574 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000575 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if (pTcon) {
577 /* no sense reconnecting to close a file that is
578 already closed */
Steve French3b795212008-11-13 19:45:32 +0000579 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000580 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000581 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400582 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000583 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700584 /* Give write a better chance to get to
585 server ahead of the close. We do not
586 want to add a wait_q here as it would
587 increase the memory utilization as
588 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000589 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700590 clear the socket */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000591 cFYI(DBG2, "close delay, write pending");
Steve French23e7dd72005-10-20 13:44:56 -0700592 msleep(timeout);
593 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000594 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000595 if (!pTcon->need_reconnect &&
596 !pSMBFile->invalidHandle)
597 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000599 } else
600 write_unlock(&GlobalSMBSeslock);
601 } else
602 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000603
604 /* Delete any outstanding lock records.
605 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000606 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000607 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
608 list_del(&li->llist);
609 kfree(li);
610 }
Roland Dreier796e5662007-05-03 04:33:45 +0000611 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000612
Steve Frenchcbe04762005-04-28 22:41:05 -0700613 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 list_del(&pSMBFile->flist);
615 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700616 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400617 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 file->private_data = NULL;
619 } else
620 rc = -EBADF;
621
Steve French4efa53f2007-09-11 05:50:53 +0000622 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (list_empty(&(CIFS_I(inode)->openFileList))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000624 cFYI(1, "closing last open instance for inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 /* if the file is not open we do not know if we can cache info
626 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000627 CIFS_I(inode)->clientCanCacheRead = false;
628 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Steve French4efa53f2007-09-11 05:50:53 +0000630 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000631 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 rc = CIFS_I(inode)->write_behind_rc;
633 FreeXid(xid);
634 return rc;
635}
636
637int cifs_closedir(struct inode *inode, struct file *file)
638{
639 int rc = 0;
640 int xid;
641 struct cifsFileInfo *pCFileStruct =
642 (struct cifsFileInfo *)file->private_data;
643 char *ptmp;
644
Joe Perchesb6b38f72010-04-21 03:50:45 +0000645 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 xid = GetXid();
648
649 if (pCFileStruct) {
650 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000651 struct cifs_sb_info *cifs_sb =
652 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 pTcon = cifs_sb->tcon;
655
Joe Perchesb6b38f72010-04-21 03:50:45 +0000656 cFYI(1, "Freeing private data in close dir");
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000657 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000658 if (!pCFileStruct->srch_inf.endOfSearch &&
659 !pCFileStruct->invalidHandle) {
660 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000661 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 cFYI(1, "Closing uncompleted readdir with rc %d",
664 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 /* not much we can do if it fails anyway, ignore rc */
666 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000667 } else
668 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
670 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000671 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000673 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000674 cifs_small_buf_release(ptmp);
675 else
676 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 kfree(file->private_data);
679 file->private_data = NULL;
680 }
681 /* BB can we lock the filestruct while this is going on? */
682 FreeXid(xid);
683 return rc;
684}
685
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000686static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
687 __u64 offset, __u8 lockType)
688{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000689 struct cifsLockInfo *li =
690 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000691 if (li == NULL)
692 return -ENOMEM;
693 li->offset = offset;
694 li->length = len;
695 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000696 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000697 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000698 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000699 return 0;
700}
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
703{
704 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 __u32 numLock = 0;
706 __u32 numUnlock = 0;
707 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000708 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000710 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000711 __u16 netfid;
712 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000713 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 length = 1 + pfLock->fl_end - pfLock->fl_start;
716 rc = -EACCES;
717 xid = GetXid();
718
Joe Perchesb6b38f72010-04-21 03:50:45 +0000719 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000721 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000722 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000725 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000727 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000729 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000730 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000733 cFYI(1, "Process suspended by mandatory locking - "
734 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000736 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000737 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000739 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000742 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 numLock = 1;
744 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000745 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000747 /* Check if unlock includes more than
748 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000750 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 lockType |= LOCKING_ANDX_SHARED_LOCK;
752 numLock = 1;
753 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 numLock = 1;
756 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 lockType |= LOCKING_ANDX_SHARED_LOCK;
759 numLock = 1;
760 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800763 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000764 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530767 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530769 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 }
Steve French08547b02006-02-28 22:39:25 +0000771 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Steve French13a6e422008-12-02 17:24:33 +0000773 if ((tcon->ses->capabilities & CAP_UNIX) &&
774 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000775 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000776 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000777 /* BB add code here to normalize offset and length to
778 account for negative length which we can not accept over the
779 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000781 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000782 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000783 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000784 posix_lock_type = CIFS_RDLCK;
785 else
786 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000787 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000788 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000789 posix_lock_type, wait_flag);
790 FreeXid(xid);
791 return rc;
792 }
793
794 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000795 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000796 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000798 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 pfLock->fl_start, 1 /* numUnlock */ ,
800 0 /* numLock */ , lockType,
801 0 /* wait flag */ );
802 pfLock->fl_type = F_UNLCK;
803 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000804 cERROR(1, "Error unlocking previously locked "
805 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 rc = 0;
807
808 } else {
809 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400810 rc = 0;
811
812 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
813 pfLock->fl_type = F_WRLCK;
814 } else {
815 rc = CIFSSMBLock(xid, tcon, netfid, length,
816 pfLock->fl_start, 0, 1,
817 lockType | LOCKING_ANDX_SHARED_LOCK,
818 0 /* wait flag */);
819 if (rc == 0) {
820 rc = CIFSSMBLock(xid, tcon, netfid,
821 length, pfLock->fl_start, 1, 0,
822 lockType |
823 LOCKING_ANDX_SHARED_LOCK,
824 0 /* wait flag */);
825 pfLock->fl_type = F_RDLCK;
826 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000827 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400828 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000829 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400830 rc = 0;
831 } else {
832 pfLock->fl_type = F_WRLCK;
833 rc = 0;
834 }
835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 }
837
838 FreeXid(xid);
839 return rc;
840 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000841
842 if (!numLock && !numUnlock) {
843 /* if no lock or unlock then nothing
844 to do since we do not know what it is */
845 FreeXid(xid);
846 return -EOPNOTSUPP;
847 }
848
849 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000850 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000851 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000852 posix_lock_type = CIFS_RDLCK;
853 else
854 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000855
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000856 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000857 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000858
Steve French13a6e422008-12-02 17:24:33 +0000859 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000860 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000861 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000862 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000863 struct cifsFileInfo *fid =
864 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000865
866 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000867 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000868 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000869 0, numLock, lockType, wait_flag);
870
871 if (rc == 0) {
872 /* For Windows locks we must store them. */
873 rc = store_file_lock(fid, length,
874 pfLock->fl_start, lockType);
875 }
876 } else if (numUnlock) {
877 /* For each stored lock that this unlock overlaps
878 completely, unlock it. */
879 int stored_rc = 0;
880 struct cifsLockInfo *li, *tmp;
881
Steve French6b70c952006-09-21 07:35:29 +0000882 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000883 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000884 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
885 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000886 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000887 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000888 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000889 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000891 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000892 if (stored_rc)
893 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000894 else {
895 list_del(&li->llist);
896 kfree(li);
897 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000898 }
899 }
Roland Dreier796e5662007-05-03 04:33:45 +0000900 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000901 }
902 }
903
Steve Frenchd634cc12005-08-26 14:42:59 -0500904 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 posix_lock_file_wait(file, pfLock);
906 FreeXid(xid);
907 return rc;
908}
909
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400910/*
911 * Set the timeout on write requests past EOF. For some servers (Windows)
912 * these calls can be very long.
913 *
914 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
915 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
916 * The 10M cutoff is totally arbitrary. A better scheme for this would be
917 * welcome if someone wants to suggest one.
918 *
919 * We may be able to do a better job with this if there were some way to
920 * declare that a file should be sparse.
921 */
922static int
923cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
924{
925 if (offset <= cifsi->server_eof)
926 return CIFS_STD_OP;
927 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
928 return CIFS_VLONG_OP;
929 else
930 return CIFS_LONG_OP;
931}
932
933/* update the file size (if needed) after a write */
934static void
935cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
936 unsigned int bytes_written)
937{
938 loff_t end_of_write = offset + bytes_written;
939
940 if (end_of_write > cifsi->server_eof)
941 cifsi->server_eof = end_of_write;
942}
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944ssize_t cifs_user_write(struct file *file, const char __user *write_data,
945 size_t write_size, loff_t *poffset)
946{
947 int rc = 0;
948 unsigned int bytes_written = 0;
949 unsigned int total_written;
950 struct cifs_sb_info *cifs_sb;
951 struct cifsTconInfo *pTcon;
952 int xid, long_op;
953 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400954 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800956 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 pTcon = cifs_sb->tcon;
959
Joe Perchesb6b38f72010-04-21 03:50:45 +0000960 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
961 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 if (file->private_data == NULL)
964 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000965 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000966
Jeff Layton838726c2008-08-28 07:54:59 -0400967 rc = generic_write_checks(file, poffset, &write_size, 0);
968 if (rc)
969 return rc;
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400973 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 for (total_written = 0; write_size > total_written;
975 total_written += bytes_written) {
976 rc = -EAGAIN;
977 while (rc == -EAGAIN) {
978 if (file->private_data == NULL) {
979 /* file has been closed on us */
980 FreeXid(xid);
981 /* if we have gotten here we have written some data
982 and blocked, and the file has been freed on us while
983 we blocked so return what we managed to write */
984 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (open_file->closePend) {
987 FreeXid(xid);
988 if (total_written)
989 return total_written;
990 else
991 return -EBADF;
992 }
993 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 /* we could deadlock if we called
995 filemap_fdatawait from here so tell
996 reopen_file not to flush data to server
997 now */
Steve French4b18f2a2008-04-29 00:06:05 +0000998 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (rc != 0)
1000 break;
1001 }
1002
1003 rc = CIFSSMBWrite(xid, pTcon,
1004 open_file->netfid,
1005 min_t(const int, cifs_sb->wsize,
1006 write_size - total_written),
1007 *poffset, &bytes_written,
1008 NULL, write_data + total_written, long_op);
1009 }
1010 if (rc || (bytes_written == 0)) {
1011 if (total_written)
1012 break;
1013 else {
1014 FreeXid(xid);
1015 return rc;
1016 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001017 } else {
1018 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001020 }
Steve French133672e2007-11-13 22:41:37 +00001021 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 15 seconds is plenty */
1023 }
1024
Steve Frencha4544342005-08-24 13:59:35 -07001025 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001028 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1029 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001030/* Do not update local mtime - server will set its actual value on write
1031 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001032 * current_fs_time(inode->i_sb);*/
1033 if (total_written > 0) {
1034 spin_lock(&inode->i_lock);
1035 if (*poffset > file->f_path.dentry->d_inode->i_size)
1036 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001038 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001040 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
1042 FreeXid(xid);
1043 return total_written;
1044}
1045
1046static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001047 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048{
1049 int rc = 0;
1050 unsigned int bytes_written = 0;
1051 unsigned int total_written;
1052 struct cifs_sb_info *cifs_sb;
1053 struct cifsTconInfo *pTcon;
1054 int xid, long_op;
1055 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001056 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001058 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 pTcon = cifs_sb->tcon;
1061
Joe Perchesb6b38f72010-04-21 03:50:45 +00001062 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
1063 *poffset, file->f_path.dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 if (file->private_data == NULL)
1066 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001067 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001071 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 for (total_written = 0; write_size > total_written;
1073 total_written += bytes_written) {
1074 rc = -EAGAIN;
1075 while (rc == -EAGAIN) {
1076 if (file->private_data == NULL) {
1077 /* file has been closed on us */
1078 FreeXid(xid);
1079 /* if we have gotten here we have written some data
1080 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001081 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 write */
1083 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (open_file->closePend) {
1086 FreeXid(xid);
1087 if (total_written)
1088 return total_written;
1089 else
1090 return -EBADF;
1091 }
1092 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 /* we could deadlock if we called
1094 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001095 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001097 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 if (rc != 0)
1099 break;
1100 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001101 if (experimEnabled || (pTcon->ses->server &&
1102 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001103 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001104 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001105 struct kvec iov[2];
1106 unsigned int len;
1107
Steve French0ae0efa2005-10-10 10:57:19 -07001108 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001109 write_size - total_written);
1110 /* iov[0] is reserved for smb header */
1111 iov[1].iov_base = (char *)write_data +
1112 total_written;
1113 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001114 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001115 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001116 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001117 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001118 } else
Steve French60808232006-04-22 15:53:05 +00001119 rc = CIFSSMBWrite(xid, pTcon,
1120 open_file->netfid,
1121 min_t(const int, cifs_sb->wsize,
1122 write_size - total_written),
1123 *poffset, &bytes_written,
1124 write_data + total_written,
1125 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
1127 if (rc || (bytes_written == 0)) {
1128 if (total_written)
1129 break;
1130 else {
1131 FreeXid(xid);
1132 return rc;
1133 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001134 } else {
1135 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001137 }
Steve French133672e2007-11-13 22:41:37 +00001138 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 15 seconds is plenty */
1140 }
1141
Steve Frencha4544342005-08-24 13:59:35 -07001142 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001145 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001146/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001147/* file->f_path.dentry->d_inode->i_ctime =
1148 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1149 if (total_written > 0) {
1150 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1151 if (*poffset > file->f_path.dentry->d_inode->i_size)
1152 i_size_write(file->f_path.dentry->d_inode,
1153 *poffset);
1154 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
Steve French3677db12007-02-26 16:46:11 +00001156 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
1158 FreeXid(xid);
1159 return total_written;
1160}
1161
Steve French630f3f02007-10-25 21:17:17 +00001162#ifdef CONFIG_CIFS_EXPERIMENTAL
1163struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1164{
1165 struct cifsFileInfo *open_file = NULL;
1166
1167 read_lock(&GlobalSMBSeslock);
1168 /* we could simply get the first_list_entry since write-only entries
1169 are always at the end of the list but since the first entry might
1170 have a close pending, we go through the whole list */
1171 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1172 if (open_file->closePend)
1173 continue;
1174 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1175 (open_file->pfile->f_flags & O_RDONLY))) {
1176 if (!open_file->invalidHandle) {
1177 /* found a good file */
1178 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001179 cifsFileInfo_get(open_file);
Steve French630f3f02007-10-25 21:17:17 +00001180 read_unlock(&GlobalSMBSeslock);
1181 return open_file;
1182 } /* else might as well continue, and look for
1183 another, or simply have the caller reopen it
1184 again rather than trying to fix this handle */
1185 } else /* write only file */
1186 break; /* write only files are last so must be done */
1187 }
1188 read_unlock(&GlobalSMBSeslock);
1189 return NULL;
1190}
1191#endif
1192
Steve Frenchdd99cd82005-10-05 19:32:49 -07001193struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001194{
1195 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001196 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001197 int rc;
Steve French6148a742005-10-05 12:23:19 -07001198
Steve French60808232006-04-22 15:53:05 +00001199 /* Having a null inode here (because mapping->host was set to zero by
1200 the VFS or MM) should not happen but we had reports of on oops (due to
1201 it being zero) during stress testcases so we need to check for it */
1202
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001203 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001204 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001205 dump_stack();
1206 return NULL;
1207 }
1208
Steve French6148a742005-10-05 12:23:19 -07001209 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001210refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001211 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001212 if (open_file->closePend ||
1213 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001214 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001215
Steve French6148a742005-10-05 12:23:19 -07001216 if (open_file->pfile &&
1217 ((open_file->pfile->f_flags & O_RDWR) ||
1218 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001219 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001220
1221 if (!open_file->invalidHandle) {
1222 /* found a good writable file */
1223 read_unlock(&GlobalSMBSeslock);
1224 return open_file;
1225 }
Steve French8840dee2007-11-16 23:05:52 +00001226
Steve French6148a742005-10-05 12:23:19 -07001227 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001228 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001229 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001230 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001231 if (!open_file->closePend)
1232 return open_file;
1233 else { /* start over in case this was deleted */
1234 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001235 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001236 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001237 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001238 }
1239 }
Steve French9b22b0b2007-10-02 01:11:08 +00001240
1241 /* if it fails, try another handle if possible -
1242 (we can not do this if closePending since
1243 loop could be modified - in which case we
1244 have to start at the beginning of the list
1245 again. Note that it would be bad
1246 to hold up writepages here (rather than
1247 in caller) with continuous retries */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001248 cFYI(1, "wp failed on reopen file");
Steve French9b22b0b2007-10-02 01:11:08 +00001249 read_lock(&GlobalSMBSeslock);
1250 /* can not use this handle, no write
1251 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001252 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001253
Steve French9b22b0b2007-10-02 01:11:08 +00001254 if (open_file->closePend) /* list could have changed */
1255 goto refind_writable;
1256 /* else we simply continue to the next entry. Thus
1257 we do not loop on reopen errors. If we
1258 can not reopen the file, for example if we
1259 reconnected to a server with another client
1260 racing to delete or lock the file we would not
1261 make progress if we restarted before the beginning
1262 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001263 }
1264 }
Jeff Layton2846d382008-09-22 21:33:33 -04001265 /* couldn't find useable FH with same pid, try any available */
1266 if (!any_available) {
1267 any_available = true;
1268 goto refind_writable;
1269 }
Steve French6148a742005-10-05 12:23:19 -07001270 read_unlock(&GlobalSMBSeslock);
1271 return NULL;
1272}
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1275{
1276 struct address_space *mapping = page->mapping;
1277 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1278 char *write_data;
1279 int rc = -EFAULT;
1280 int bytes_written = 0;
1281 struct cifs_sb_info *cifs_sb;
1282 struct cifsTconInfo *pTcon;
1283 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001284 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 if (!mapping || !mapping->host)
1287 return -EFAULT;
1288
1289 inode = page->mapping->host;
1290 cifs_sb = CIFS_SB(inode->i_sb);
1291 pTcon = cifs_sb->tcon;
1292
1293 offset += (loff_t)from;
1294 write_data = kmap(page);
1295 write_data += from;
1296
1297 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1298 kunmap(page);
1299 return -EIO;
1300 }
1301
1302 /* racing with truncate? */
1303 if (offset > mapping->host->i_size) {
1304 kunmap(page);
1305 return 0; /* don't care */
1306 }
1307
1308 /* check to make sure that we are not extending the file */
1309 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001310 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Steve French6148a742005-10-05 12:23:19 -07001312 open_file = find_writable_file(CIFS_I(mapping->host));
1313 if (open_file) {
1314 bytes_written = cifs_write(open_file->pfile, write_data,
1315 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001316 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001318 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001319 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001320 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001321 else if (bytes_written < 0)
1322 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001323 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001324 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 rc = -EIO;
1326 }
1327
1328 kunmap(page);
1329 return rc;
1330}
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001333 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334{
Steve French37c0eb42005-10-05 14:50:29 -07001335 struct backing_dev_info *bdi = mapping->backing_dev_info;
1336 unsigned int bytes_to_write;
1337 unsigned int bytes_written;
1338 struct cifs_sb_info *cifs_sb;
1339 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001340 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001341 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001342 int range_whole = 0;
1343 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001344 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001345 int n_iov = 0;
1346 pgoff_t next;
1347 int nr_pages;
1348 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001349 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001350 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001351 struct page *page;
1352 struct pagevec pvec;
1353 int rc = 0;
1354 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001355 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Steve French37c0eb42005-10-05 14:50:29 -07001357 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001358
Steve French37c0eb42005-10-05 14:50:29 -07001359 /*
1360 * If wsize is smaller that the page cache size, default to writing
1361 * one page at a time via cifs_writepage
1362 */
1363 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1364 return generic_writepages(mapping, wbc);
1365
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001366 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1367 if (cifs_sb->tcon->ses->server->secMode &
1368 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1369 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001370 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001371
Steve French9a0c8232007-02-02 04:21:57 +00001372 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001373 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001374 return generic_writepages(mapping, wbc);
1375
1376
Steve French37c0eb42005-10-05 14:50:29 -07001377 /*
1378 * BB: Is this meaningful for a non-block-device file system?
1379 * If it is, we should test it again after we do I/O
1380 */
1381 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1382 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001383 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001384 return 0;
1385 }
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 xid = GetXid();
1388
Steve French37c0eb42005-10-05 14:50:29 -07001389 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001390 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001391 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001392 end = -1;
1393 } else {
1394 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1395 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1396 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1397 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001398 scanned = 1;
1399 }
1400retry:
1401 while (!done && (index <= end) &&
1402 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1403 PAGECACHE_TAG_DIRTY,
1404 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1405 int first;
1406 unsigned int i;
1407
Steve French37c0eb42005-10-05 14:50:29 -07001408 first = -1;
1409 next = 0;
1410 n_iov = 0;
1411 bytes_to_write = 0;
1412
1413 for (i = 0; i < nr_pages; i++) {
1414 page = pvec.pages[i];
1415 /*
1416 * At this point we hold neither mapping->tree_lock nor
1417 * lock on the page itself: the page may be truncated or
1418 * invalidated (changing page->mapping to NULL), or even
1419 * swizzled back from swapper_space to tmpfs file
1420 * mapping
1421 */
1422
1423 if (first < 0)
1424 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001425 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001426 break;
1427
1428 if (unlikely(page->mapping != mapping)) {
1429 unlock_page(page);
1430 break;
1431 }
1432
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001433 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001434 done = 1;
1435 unlock_page(page);
1436 break;
1437 }
1438
1439 if (next && (page->index != next)) {
1440 /* Not next consecutive page */
1441 unlock_page(page);
1442 break;
1443 }
1444
1445 if (wbc->sync_mode != WB_SYNC_NONE)
1446 wait_on_page_writeback(page);
1447
1448 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001449 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001450 unlock_page(page);
1451 break;
1452 }
Steve French84d2f072005-10-12 15:32:05 -07001453
Linus Torvaldscb876f42006-12-23 16:19:07 -08001454 /*
1455 * This actually clears the dirty bit in the radix tree.
1456 * See cifs_writepage() for more commentary.
1457 */
1458 set_page_writeback(page);
1459
Steve French84d2f072005-10-12 15:32:05 -07001460 if (page_offset(page) >= mapping->host->i_size) {
1461 done = 1;
1462 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001463 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001464 break;
1465 }
1466
Steve French37c0eb42005-10-05 14:50:29 -07001467 /*
1468 * BB can we get rid of this? pages are held by pvec
1469 */
1470 page_cache_get(page);
1471
Steve French84d2f072005-10-12 15:32:05 -07001472 len = min(mapping->host->i_size - page_offset(page),
1473 (loff_t)PAGE_CACHE_SIZE);
1474
Steve French37c0eb42005-10-05 14:50:29 -07001475 /* reserve iov[0] for the smb header */
1476 n_iov++;
1477 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001478 iov[n_iov].iov_len = len;
1479 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001480
1481 if (first < 0) {
1482 first = i;
1483 offset = page_offset(page);
1484 }
1485 next = page->index + 1;
1486 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1487 break;
1488 }
1489 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001490 /* Search for a writable handle every time we call
1491 * CIFSSMBWrite2. We can't rely on the last handle
1492 * we used to still be valid
1493 */
1494 open_file = find_writable_file(CIFS_I(mapping->host));
1495 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001496 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001497 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001498 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001499 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001500 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1501 open_file->netfid,
1502 bytes_to_write, offset,
1503 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001504 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001505 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001506 cifs_update_eof(cifsi, offset, bytes_written);
1507
Steve French23e7dd72005-10-20 13:44:56 -07001508 if (rc || bytes_written < bytes_to_write) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001509 cERROR(1, "Write2 ret %d, wrote %d",
1510 rc, bytes_written);
Steve French23e7dd72005-10-20 13:44:56 -07001511 /* BB what if continued retry is
1512 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001513 if (rc == -ENOSPC)
1514 set_bit(AS_ENOSPC, &mapping->flags);
1515 else
1516 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001517 } else {
1518 cifs_stats_bytes_written(cifs_sb->tcon,
1519 bytes_written);
1520 }
Steve French37c0eb42005-10-05 14:50:29 -07001521 }
1522 for (i = 0; i < n_iov; i++) {
1523 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001524 /* Should we also set page error on
1525 success rc but too little data written? */
1526 /* BB investigate retry logic on temporary
1527 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001528 when page marked as error */
1529 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001530 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001531 kunmap(page);
1532 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001533 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001534 page_cache_release(page);
1535 }
1536 if ((wbc->nr_to_write -= n_iov) <= 0)
1537 done = 1;
1538 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001539 } else
1540 /* Need to re-find the pages we skipped */
1541 index = pvec.pages[0]->index + 1;
1542
Steve French37c0eb42005-10-05 14:50:29 -07001543 pagevec_release(&pvec);
1544 }
1545 if (!scanned && !done) {
1546 /*
1547 * We hit the last page and there is more work to be done: wrap
1548 * back to the start of the file
1549 */
1550 scanned = 1;
1551 index = 0;
1552 goto retry;
1553 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001554 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001555 mapping->writeback_index = index;
1556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001558 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return rc;
1560}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001562static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
1564 int rc = -EFAULT;
1565 int xid;
1566
1567 xid = GetXid();
1568/* BB add check for wbc flags */
1569 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001570 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001571 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001572
1573 /*
1574 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1575 *
1576 * A writepage() implementation always needs to do either this,
1577 * or re-dirty the page with "redirty_page_for_writepage()" in
1578 * the case of a failure.
1579 *
1580 * Just unlocking the page will cause the radix tree tag-bits
1581 * to fail to update with the state of the page correctly.
1582 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001583 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1585 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1586 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001587 end_page_writeback(page);
1588 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 FreeXid(xid);
1590 return rc;
1591}
1592
Nick Piggind9414772008-09-24 11:32:59 -04001593static int cifs_write_end(struct file *file, struct address_space *mapping,
1594 loff_t pos, unsigned len, unsigned copied,
1595 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596{
Nick Piggind9414772008-09-24 11:32:59 -04001597 int rc;
1598 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
Joe Perchesb6b38f72010-04-21 03:50:45 +00001600 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1601 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001602
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001603 if (PageChecked(page)) {
1604 if (copied == len)
1605 SetPageUptodate(page);
1606 ClearPageChecked(page);
1607 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001608 SetPageUptodate(page);
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001611 char *page_data;
1612 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1613 int xid;
1614
1615 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* this is probably better than directly calling
1617 partialpage_write since in this function the file handle is
1618 known which we might as well leverage */
1619 /* BB check if anything else missing out of ppw
1620 such as updating last write time */
1621 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001622 rc = cifs_write(file, page_data + offset, copied, &pos);
1623 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001625
1626 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001627 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001628 rc = copied;
1629 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 set_page_dirty(page);
1631 }
1632
Nick Piggind9414772008-09-24 11:32:59 -04001633 if (rc > 0) {
1634 spin_lock(&inode->i_lock);
1635 if (pos > inode->i_size)
1636 i_size_write(inode, pos);
1637 spin_unlock(&inode->i_lock);
1638 }
1639
1640 unlock_page(page);
1641 page_cache_release(page);
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 return rc;
1644}
1645
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001646int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
1648 int xid;
1649 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001650 struct cifsTconInfo *tcon;
1651 struct cifsFileInfo *smbfile =
1652 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001653 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 xid = GetXid();
1656
Joe Perchesb6b38f72010-04-21 03:50:45 +00001657 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001658 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001659
Jeff Laytoncea21802007-11-20 23:19:03 +00001660 rc = filemap_write_and_wait(inode->i_mapping);
1661 if (rc == 0) {
1662 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001664 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001665 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001666 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001667 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001668 }
Steve Frenchb298f222009-02-21 21:17:43 +00001669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 FreeXid(xid);
1671 return rc;
1672}
1673
NeilBrown3978d712006-03-26 01:37:17 -08001674/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675{
1676 struct address_space *mapping;
1677 struct inode *inode;
1678 unsigned long index = page->index;
1679 unsigned int rpages = 0;
1680 int rc = 0;
1681
Steve Frenchf19159d2010-04-21 04:12:10 +00001682 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 mapping = page->mapping;
1684 if (!mapping)
1685 return 0;
1686 inode = mapping->host;
1687 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001688 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001690/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1692
Joe Perchesb6b38f72010-04-21 03:50:45 +00001693/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
NeilBrown3978d712006-03-26 01:37:17 -08001695#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 if (rc < 0)
1697 return rc;
1698 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001699#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700} */
1701
1702/*
1703 * As file closes, flush all cached write data for this inode checking
1704 * for write behind errors.
1705 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001706int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001708 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 int rc = 0;
1710
1711 /* Rather than do the steps manually:
1712 lock the inode for writing
1713 loop through pages looking for write behind data (dirty pages)
1714 coalesce into contiguous 16K (or smaller) chunks to write to server
1715 send to server (prefer in parallel)
1716 deal with writebehind errors
1717 unlock inode for writing
1718 filemapfdatawrite appears easier for the time being */
1719
1720 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001721 /* reset wb rc if we were able to write out dirty pages */
1722 if (!rc) {
1723 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001725 }
Steve French50c2f752007-07-13 00:33:32 +00001726
Joe Perchesb6b38f72010-04-21 03:50:45 +00001727 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 return rc;
1730}
1731
1732ssize_t cifs_user_read(struct file *file, char __user *read_data,
1733 size_t read_size, loff_t *poffset)
1734{
1735 int rc = -EACCES;
1736 unsigned int bytes_read = 0;
1737 unsigned int total_read = 0;
1738 unsigned int current_read_size;
1739 struct cifs_sb_info *cifs_sb;
1740 struct cifsTconInfo *pTcon;
1741 int xid;
1742 struct cifsFileInfo *open_file;
1743 char *smb_read_data;
1744 char __user *current_offset;
1745 struct smb_com_read_rsp *pSMBr;
1746
1747 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001748 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 pTcon = cifs_sb->tcon;
1750
1751 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301752 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301754 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 }
1756 open_file = (struct cifsFileInfo *)file->private_data;
1757
Steve Frenchad7a2922008-02-07 23:25:02 +00001758 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001759 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 for (total_read = 0, current_offset = read_data;
1762 read_size > total_read;
1763 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001764 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 cifs_sb->rsize);
1766 rc = -EAGAIN;
1767 smb_read_data = NULL;
1768 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001769 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001770 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001772 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 if (rc != 0)
1774 break;
1775 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001776 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001777 open_file->netfid,
1778 current_read_size, *poffset,
1779 &bytes_read, &smb_read_data,
1780 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001783 if (copy_to_user(current_offset,
1784 smb_read_data +
1785 4 /* RFC1001 length field */ +
1786 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001787 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001788 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001789
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001791 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001792 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001793 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 smb_read_data = NULL;
1795 }
1796 }
1797 if (rc || (bytes_read == 0)) {
1798 if (total_read) {
1799 break;
1800 } else {
1801 FreeXid(xid);
1802 return rc;
1803 }
1804 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001805 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 *poffset += bytes_read;
1807 }
1808 }
1809 FreeXid(xid);
1810 return total_read;
1811}
1812
1813
1814static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1815 loff_t *poffset)
1816{
1817 int rc = -EACCES;
1818 unsigned int bytes_read = 0;
1819 unsigned int total_read;
1820 unsigned int current_read_size;
1821 struct cifs_sb_info *cifs_sb;
1822 struct cifsTconInfo *pTcon;
1823 int xid;
1824 char *current_offset;
1825 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001826 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
1828 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001829 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 pTcon = cifs_sb->tcon;
1831
1832 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301833 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301835 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
1837 open_file = (struct cifsFileInfo *)file->private_data;
1838
1839 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001840 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001842 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 read_size > total_read;
1844 total_read += bytes_read, current_offset += bytes_read) {
1845 current_read_size = min_t(const int, read_size - total_read,
1846 cifs_sb->rsize);
Steve Frenchf9f5c812005-09-15 23:06:38 -07001847 /* For windows me and 9x we do not want to request more
1848 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001849 if ((pTcon->ses) &&
Steve Frenchf9f5c812005-09-15 23:06:38 -07001850 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1851 current_read_size = min_t(const int, current_read_size,
1852 pTcon->ses->server->maxBuf - 128);
1853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 rc = -EAGAIN;
1855 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001856 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001858 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if (rc != 0)
1860 break;
1861 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001862 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001863 open_file->netfid,
1864 current_read_size, *poffset,
1865 &bytes_read, &current_offset,
1866 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 }
1868 if (rc || (bytes_read == 0)) {
1869 if (total_read) {
1870 break;
1871 } else {
1872 FreeXid(xid);
1873 return rc;
1874 }
1875 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001876 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 *poffset += bytes_read;
1878 }
1879 }
1880 FreeXid(xid);
1881 return total_read;
1882}
1883
1884int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1885{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 int rc, xid;
1887
1888 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001889 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001891 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 FreeXid(xid);
1893 return rc;
1894 }
1895 rc = generic_file_mmap(file, vma);
1896 FreeXid(xid);
1897 return rc;
1898}
1899
1900
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001901static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001902 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
1904 struct page *page;
1905 char *target;
1906
1907 while (bytes_read > 0) {
1908 if (list_empty(pages))
1909 break;
1910
1911 page = list_entry(pages->prev, struct page, lru);
1912 list_del(&page->lru);
1913
Nick Piggin315e9952010-04-21 03:18:28 +00001914 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 GFP_KERNEL)) {
1916 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001917 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001918 data += PAGE_CACHE_SIZE;
1919 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 continue;
1921 }
Jeff Layton06b43672010-06-01 10:54:45 -04001922 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001924 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
1926 if (PAGE_CACHE_SIZE > bytes_read) {
1927 memcpy(target, data, bytes_read);
1928 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001929 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 PAGE_CACHE_SIZE - bytes_read);
1931 bytes_read = 0;
1932 } else {
1933 memcpy(target, data, PAGE_CACHE_SIZE);
1934 bytes_read -= PAGE_CACHE_SIZE;
1935 }
1936 kunmap_atomic(target, KM_USER0);
1937
1938 flush_dcache_page(page);
1939 SetPageUptodate(page);
1940 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 data += PAGE_CACHE_SIZE;
1942 }
1943 return;
1944}
1945
1946static int cifs_readpages(struct file *file, struct address_space *mapping,
1947 struct list_head *page_list, unsigned num_pages)
1948{
1949 int rc = -EACCES;
1950 int xid;
1951 loff_t offset;
1952 struct page *page;
1953 struct cifs_sb_info *cifs_sb;
1954 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001955 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001956 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 char *smb_read_data = NULL;
1958 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001960 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
1962 xid = GetXid();
1963 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301964 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301966 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 }
1968 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001969 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001971
Steve Frenchf19159d2010-04-21 04:12:10 +00001972 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 for (i = 0; i < num_pages; ) {
1974 unsigned contig_pages;
1975 struct page *tmp_page;
1976 unsigned long expected_index;
1977
1978 if (list_empty(page_list))
1979 break;
1980
1981 page = list_entry(page_list->prev, struct page, lru);
1982 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1983
1984 /* count adjacent pages that we will read into */
1985 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001986 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001988 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 if (tmp_page->index == expected_index) {
1990 contig_pages++;
1991 expected_index++;
1992 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001993 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
1995 if (contig_pages + i > num_pages)
1996 contig_pages = num_pages - i;
1997
1998 /* for reads over a certain size could initiate async
1999 read ahead */
2000
2001 read_size = contig_pages * PAGE_CACHE_SIZE;
2002 /* Read size needs to be in multiples of one page */
2003 read_size = min_t(const unsigned int, read_size,
2004 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002005 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
2006 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 rc = -EAGAIN;
2008 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002009 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002011 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if (rc != 0)
2013 break;
2014 }
2015
Steve Frenchbfa0d752005-08-31 21:50:37 -07002016 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002017 open_file->netfid,
2018 read_size, offset,
2019 &bytes_read, &smb_read_data,
2020 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002021 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002022 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002024 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002025 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002026 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002027 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 smb_read_data = NULL;
2029 }
2030 }
2031 }
2032 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002033 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 break;
2035 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002036 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2038 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2039 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002040 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
2042 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002043 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002044 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 i++; /* account for partial page */
2046
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002049 /* BB do we need to verify this common case ?
2050 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 we will hit it on next read */
2052
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002053 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
2055 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002056 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002057 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002058 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 break;
2062 }
2063 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002064 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002065 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002067 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 smb_read_data = NULL;
2069 }
2070 bytes_read = 0;
2071 }
2072
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073/* need to free smb_read_data buf before exit */
2074 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002075 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002076 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002077 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002078 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 FreeXid(xid);
2083 return rc;
2084}
2085
2086static int cifs_readpage_worker(struct file *file, struct page *page,
2087 loff_t *poffset)
2088{
2089 char *read_data;
2090 int rc;
2091
2092 page_cache_get(page);
2093 read_data = kmap(page);
2094 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002097
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 if (rc < 0)
2099 goto io_error;
2100 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002101 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002102
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002103 file->f_path.dentry->d_inode->i_atime =
2104 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002105
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 if (PAGE_CACHE_SIZE > rc)
2107 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2108
2109 flush_dcache_page(page);
2110 SetPageUptodate(page);
2111 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002114 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 page_cache_release(page);
2116 return rc;
2117}
2118
2119static int cifs_readpage(struct file *file, struct page *page)
2120{
2121 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2122 int rc = -EACCES;
2123 int xid;
2124
2125 xid = GetXid();
2126
2127 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302128 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302130 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 }
2132
Joe Perchesb6b38f72010-04-21 03:50:45 +00002133 cFYI(1, "readpage %p at offset %d 0x%x\n",
2134 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 rc = cifs_readpage_worker(file, page, &offset);
2137
2138 unlock_page(page);
2139
2140 FreeXid(xid);
2141 return rc;
2142}
2143
Steve Frencha403a0a2007-07-26 15:54:16 +00002144static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2145{
2146 struct cifsFileInfo *open_file;
2147
2148 read_lock(&GlobalSMBSeslock);
2149 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2150 if (open_file->closePend)
2151 continue;
2152 if (open_file->pfile &&
2153 ((open_file->pfile->f_flags & O_RDWR) ||
2154 (open_file->pfile->f_flags & O_WRONLY))) {
2155 read_unlock(&GlobalSMBSeslock);
2156 return 1;
2157 }
2158 }
2159 read_unlock(&GlobalSMBSeslock);
2160 return 0;
2161}
2162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163/* We do not want to update the file size from server for inodes
2164 open for write - to avoid races with writepage extending
2165 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002166 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 but this is tricky to do without racing with writebehind
2168 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002169bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170{
Steve Frencha403a0a2007-07-26 15:54:16 +00002171 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002172 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002173
Steve Frencha403a0a2007-07-26 15:54:16 +00002174 if (is_inode_writable(cifsInode)) {
2175 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002176 struct cifs_sb_info *cifs_sb;
2177
Steve Frenchc32a0b62006-01-12 14:41:28 -08002178 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002179 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002180 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002181 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002182 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002183 }
2184
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002185 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002186 return true;
Steve French7ba52632007-02-08 18:14:13 +00002187
Steve French4b18f2a2008-04-29 00:06:05 +00002188 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002189 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002190 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191}
2192
Nick Piggind9414772008-09-24 11:32:59 -04002193static int cifs_write_begin(struct file *file, struct address_space *mapping,
2194 loff_t pos, unsigned len, unsigned flags,
2195 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196{
Nick Piggind9414772008-09-24 11:32:59 -04002197 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2198 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002199 loff_t page_start = pos & PAGE_MASK;
2200 loff_t i_size;
2201 struct page *page;
2202 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Joe Perchesb6b38f72010-04-21 03:50:45 +00002204 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002205
Nick Piggin54566b22009-01-04 12:00:53 -08002206 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002207 if (!page) {
2208 rc = -ENOMEM;
2209 goto out;
2210 }
Nick Piggind9414772008-09-24 11:32:59 -04002211
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002212 if (PageUptodate(page))
2213 goto out;
Steve French8a236262007-03-06 00:31:00 +00002214
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002215 /*
2216 * If we write a full page it will be up to date, no need to read from
2217 * the server. If the write is short, we'll end up doing a sync write
2218 * instead.
2219 */
2220 if (len == PAGE_CACHE_SIZE)
2221 goto out;
2222
2223 /*
2224 * optimize away the read when we have an oplock, and we're not
2225 * expecting to use any of the data we'd be reading in. That
2226 * is, when the page lies beyond the EOF, or straddles the EOF
2227 * and the write will cover all of the existing data.
2228 */
2229 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2230 i_size = i_size_read(mapping->host);
2231 if (page_start >= i_size ||
2232 (offset == 0 && (pos + len) >= i_size)) {
2233 zero_user_segments(page, 0, offset,
2234 offset + len,
2235 PAGE_CACHE_SIZE);
2236 /*
2237 * PageChecked means that the parts of the page
2238 * to which we're not writing are considered up
2239 * to date. Once the data is copied to the
2240 * page, it can be set uptodate.
2241 */
2242 SetPageChecked(page);
2243 goto out;
2244 }
2245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Nick Piggind9414772008-09-24 11:32:59 -04002247 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002248 /*
2249 * might as well read a page, it is fast enough. If we get
2250 * an error, we don't need to return it. cifs_write_end will
2251 * do a sync write instead since PG_uptodate isn't set.
2252 */
2253 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002254 } else {
2255 /* we could try using another file handle if there is one -
2256 but how would we lock it to prevent close of that handle
2257 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002258 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002259 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002260out:
2261 *pagep = page;
2262 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263}
2264
Jeff Layton3bc303c2009-09-21 06:47:50 -04002265static void
2266cifs_oplock_break(struct slow_work *work)
2267{
2268 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2269 oplock_break);
2270 struct inode *inode = cfile->pInode;
2271 struct cifsInodeInfo *cinode = CIFS_I(inode);
2272 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2273 int rc, waitrc = 0;
2274
2275 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002276 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002277 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002278 else
Al Viro8737c932009-12-24 06:47:55 -05002279 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002280 rc = filemap_fdatawrite(inode->i_mapping);
2281 if (cinode->clientCanCacheRead == 0) {
2282 waitrc = filemap_fdatawait(inode->i_mapping);
2283 invalidate_remote_inode(inode);
2284 }
2285 if (!rc)
2286 rc = waitrc;
2287 if (rc)
2288 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002289 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002290 }
2291
2292 /*
2293 * releasing stale oplock after recent reconnect of smb session using
2294 * a now incorrect file handle is not a data integrity issue but do
2295 * not bother sending an oplock release if session to server still is
2296 * disconnected since oplock already released by the server
2297 */
2298 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2299 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2300 LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002301 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002302 }
2303}
2304
2305static int
2306cifs_oplock_break_get(struct slow_work *work)
2307{
2308 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2309 oplock_break);
2310 mntget(cfile->mnt);
2311 cifsFileInfo_get(cfile);
2312 return 0;
2313}
2314
2315static void
2316cifs_oplock_break_put(struct slow_work *work)
2317{
2318 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2319 oplock_break);
2320 mntput(cfile->mnt);
2321 cifsFileInfo_put(cfile);
2322}
2323
2324const struct slow_work_ops cifs_oplock_break_ops = {
2325 .get_ref = cifs_oplock_break_get,
2326 .put_ref = cifs_oplock_break_put,
2327 .execute = cifs_oplock_break,
2328};
2329
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002330const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 .readpage = cifs_readpage,
2332 .readpages = cifs_readpages,
2333 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002334 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002335 .write_begin = cifs_write_begin,
2336 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 .set_page_dirty = __set_page_dirty_nobuffers,
2338 /* .sync_page = cifs_sync_page, */
2339 /* .direct_IO = */
2340};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002341
2342/*
2343 * cifs_readpages requires the server to support a buffer large enough to
2344 * contain the header plus one complete page of data. Otherwise, we need
2345 * to leave cifs_readpages out of the address space operations.
2346 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002347const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002348 .readpage = cifs_readpage,
2349 .writepage = cifs_writepage,
2350 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002351 .write_begin = cifs_write_begin,
2352 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002353 .set_page_dirty = __set_page_dirty_nobuffers,
2354 /* .sync_page = cifs_sync_page, */
2355 /* .direct_IO = */
2356};